#include "Client.h" #include "Keyboard.h" #include "Layer.h" #include "Mouse.h" #include "Screen.h" #include "Window.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include static constexpr uid_t WIND_USER_ID = 2; static constexpr gid_t WIND_GROUP_ID = 2; static constexpr gid_t WSYS_GROUP_ID = 3; Result luna_main(int argc, char** argv) { srand((unsigned)time(NULL)); TRY(os::Security::pledge("stdio rpath wpath cpath unix tty id", NULL)); StringView socket_path = "/tmp/wind.sock"; StringView system_socket_path = "/tmp/wsys.sock"; os::ArgumentParser parser; parser.add_description("The display server for Luna's graphical user interface."_sv); parser.add_system_program_info("wind"_sv); parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv); parser.add_value_argument(system_socket_path, ' ', "system-socket"_sv, "the path for the system IPC socket, for privileged clients"_sv); parser.parse(argc, argv); if (geteuid() != 0) { os::eprintln("error: wind must be run as root to initialize resources, the server will drop " "privileges automatically afterwards"); return 1; } auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly)); mouse->set_buffer(os::File::NotBuffered); mouse->set_close_on_exec(); auto keyboard = TRY(os::File::open("/dev/kbd", os::File::ReadOnly)); keyboard->set_buffer(os::File::NotBuffered); keyboard->set_close_on_exec(); TRY(Screen::open()); auto& screen = Screen::the(); Mouse mouse_pointer { screen.canvas() }; umask(0002); // Set permissions to wind:wsys temporarily, to create /tmp/wsys.sock with those privileges. setegid(WSYS_GROUP_ID); seteuid(WIND_USER_ID); auto system_server = TRY(os::LocalServer::create(system_socket_path, false)); TRY(system_server->listen(20)); seteuid(0); // Opened all necessary files as root, drop privileges now. setgid(WIND_GROUP_ID); setuid(WIND_USER_ID); auto server = TRY(os::LocalServer::create(socket_path, false)); TRY(server->listen(20)); int fd = open("/dev/null", O_RDONLY); if (fd >= 0) { dup2(fd, STDIN_FILENO); close(fd); } // We're ready now. os::IPC::notify_parent(); ui::Color background = ui::Color::from_rgb(0x10, 0x10, 0x10); Vector> clients; Vector fds; TRY(fds.try_append({ .fd = mouse->fd(), .events = POLLIN, .revents = 0 })); TRY(fds.try_append({ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 })); TRY(fds.try_append({ .fd = server->fd(), .events = POLLIN, .revents = 0 })); TRY(fds.try_append({ .fd = system_server->fd(), .events = POLLIN, .revents = 0 })); TRY(os::Security::pledge("stdio rpath wpath cpath unix", NULL)); while (1) { screen.canvas().fill(background); Layer::draw_all_windows(screen.canvas()); mouse_pointer.draw(screen.canvas()); screen.sync(); for (auto& pfd : fds) { pfd.revents = 0; } int rc = poll(fds.data(), fds.size(), 1000); if (!rc) continue; if (rc < 0 && errno != EINTR) { os::println("poll: error: %s", strerror(errno)); } if (fds[0].revents & POLLIN) { moon::MousePacket packet; TRY(mouse->read_typed(packet)); mouse_pointer.update(packet); } if (fds[1].revents & POLLIN) { moon::KeyboardPacket packet; TRY(keyboard->read_typed(packet)); auto request = wind::Keyboard::decode_keyboard_event((moon::KeyCode)packet.key, packet.released); if (auto* window = Layer::focused_window()) { request.window = window->id; window->client->conn->send_async(request); } } if (fds[2].revents & POLLIN) { auto client = TRY(server->accept()); os::println("wind: New client connected!"); TRY(fds.try_append({ .fd = client.fd(), .events = POLLIN, .revents = 0 })); auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client))); OwnedPtr c = TRY(adopt_owned_if_nonnull(new Client(move(connection), EMPTY_PLEDGE))); TRY(clients.try_append(move(c))); } if (fds[3].revents & POLLIN) { auto client = TRY(system_server->accept()); os::println("wind: New privileged client connected!"); TRY(fds.try_append({ .fd = client.fd(), .events = POLLIN, .revents = 0 })); auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client))); OwnedPtr c = TRY(adopt_owned_if_nonnull(new Client(move(connection), HAS_NOT_YET_PLEDGED))); TRY(clients.try_append(move(c))); } for (usize i = 0; i < clients.size(); i++) { if (fds[i + 4].revents & POLLIN) clients[i]->conn->check_for_messages(); if (fds[i + 4].revents & POLLHUP) clients[i]->should_be_disconnected = true; if (clients[i]->should_be_disconnected) { os::println("wind: Client %zu disconnected", i); fds.remove_at(i + 4); auto client = clients.remove_at(i); client->conn->disconnect(); for (auto& window : client->windows) { if (window) { window->layer->windows.remove(window); mouse_pointer.window_did_close(window); delete window; } } } } } }