Luna/gui/wind/main.cpp

177 lines
5.9 KiB
C++
Raw Permalink Normal View History

2023-08-14 16:15:29 +00:00
#include "Client.h"
#include "Keyboard.h"
#include "Layer.h"
#include "Mouse.h"
#include "Screen.h"
2023-08-03 15:38:49 +00:00
#include "Window.h"
#include <errno.h>
#include <moon/Keyboard.h>
#include <os/ArgumentParser.h>
#include <os/File.h>
#include <os/IPC.h>
2023-08-03 14:40:17 +00:00
#include <os/LocalServer.h>
#include <os/Process.h>
2023-08-14 09:07:19 +00:00
#include <os/Security.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
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<int> luna_main(int argc, char** argv)
{
srand((unsigned)time(NULL));
TRY(os::Security::pledge("stdio rpath wpath cpath unix tty id", NULL));
2023-08-14 09:07:19 +00:00
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();
2023-09-14 20:51:19 +00:00
ui::Color background = ui::Color::from_rgb(0x10, 0x10, 0x10);
Vector<OwnedPtr<Client>> clients;
Vector<struct pollfd> 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 }));
2023-08-03 14:40:17 +00:00
TRY(os::Security::pledge("stdio rpath wpath cpath unix", NULL));
2023-08-14 09:07:19 +00:00
while (1)
{
2023-08-03 15:38:49 +00:00
screen.canvas().fill(background);
Layer::draw_all_windows(screen.canvas());
2023-08-03 15:38:49 +00:00
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));
2023-08-03 15:38:49 +00:00
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<Client> 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<Client> 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)
2023-08-14 16:15:29 +00:00
{
if (window)
{
window->layer->windows.remove(window);
mouse_pointer.window_did_close(window);
delete window;
}
2023-08-14 16:15:29 +00:00
}
}
}
}
}