diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 7e59203..bb8904a 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -20,7 +20,7 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/dri/card0 + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/dri/card0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/dri/card0 - check-format: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 185d232..da300c8 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -19,7 +19,7 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0 + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 - smoketest-logind: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index c8f9618..b4bc7da 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -15,6 +15,6 @@ tasks: meson -Db_lundef=false -Db_sanitize=address -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled -Dlibseat-logind=disabled build seatd ninja -C build sudo ninja -C build install - timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0 + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 diff --git a/.builds/netbsd.yml b/.builds/netbsd.yml deleted file mode 100644 index a676138..0000000 --- a/.builds/netbsd.yml +++ /dev/null @@ -1,24 +0,0 @@ -image: netbsd/latest -packages: - - meson -sources: - - https://git.sr.ht/~kennylevinsen/seatd -tasks: - - wscons: | - echo 'wscons=YES' | sudo tee -a /etc/rc.conf - sudo /etc/rc.d/wscons start - sudo /etc/rc.d/ttys restart - - prepare: | - meson -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dlibseat-logind=disabled build seatd - - build: | - ninja -C build - - unittest: | - ninja -C build test - - smoketest: | - rm -rf build - meson -Db_lundef=false -Db_sanitize=address -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled -Dlibseat-logind=disabled build seatd - ninja -C build - sudo ninja -C build install - timeout -s SIGKILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/wskbd - - smoketest-builtin: | - timeout -s SIGKILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/wskbd diff --git a/README.md b/README.md index b8a705f..9aa9e99 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A minimal seat management daemon, and a universal seat management library. -Currently supports Linux and FreeBSD, and has experimental NetBSD support. +Currently supports Linux and FreeBSD. ## What is seat management? @@ -43,4 +43,4 @@ Instead of giving user shell developers more work, libseat aims to make supporti ## How to discuss -Go to [#kennylevinsen @ irc.libera.chat](ircs://irc.libera.chat/#kennylevinsen) to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). +Go to #kennylevinsen @ irc.libera.chat to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). diff --git a/common/drm.c b/common/drm.c index 2fbadd5..9591dc0 100644 --- a/common/drm.c +++ b/common/drm.c @@ -2,6 +2,10 @@ #include #include +#if defined(__linux__) +#include +#endif + #include "drm.h" // From libdrm @@ -10,8 +14,7 @@ #define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) #define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) -#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) -#define STR_HAS_PREFIX(prefix, s) (strncmp(prefix, s, STRLEN(prefix)) == 0) +#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) int drm_set_master(int fd) { return ioctl(fd, DRM_IOCTL_SET_MASTER, 0); @@ -21,20 +24,21 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__linux__) int path_is_drm(const char *path) { - if (STR_HAS_PREFIX("/dev/dri/", path)) - return 1; - return 0; + static const char prefix[] = "/dev/dri/"; + static const int prefixlen = STRLEN(prefix); + return strncmp(prefix, path, prefixlen) == 0; +} + +int dev_is_drm(dev_t device) { + return major(device) == 226; } #elif defined(__FreeBSD__) int path_is_drm(const char *path) { - if (STR_HAS_PREFIX("/dev/dri/", path)) - return 1; - /* Some drivers have /dev/dri/X symlinked to /dev/drm/X */ - if (STR_HAS_PREFIX("/dev/drm/", path)) - return 1; - return 0; + static const char prefix[] = "/dev/drm/"; + static const int prefixlen = STRLEN(prefix); + return strncmp(prefix, path, prefixlen) == 0; } #else #error Unsupported platform diff --git a/common/evdev.c b/common/evdev.c index a77bf36..4aff9bc 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -9,13 +9,14 @@ #include #elif defined(__FreeBSD__) #include +#else +#error Unsupported platform #endif #include "evdev.h" #define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) -#if defined(__linux__) || defined(__FreeBSD__) int path_is_evdev(const char *path) { static const char prefix[] = "/dev/input/event"; static const size_t prefixlen = STRLEN(prefix); @@ -25,15 +26,9 @@ int path_is_evdev(const char *path) { int evdev_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } -#elif defined(__NetBSD__) || defined(__OpenBSD__) -int path_is_evdev(const char *path) { - (void)path; - return 0; + +#if defined(__linux__) +int dev_is_evdev(dev_t device) { + return major(device) == INPUT_MAJOR; } -int evdev_revoke(int fd) { - (void)fd; - return 0; -} -#else -#error Unsupported platform #endif diff --git a/common/terminal.c b/common/terminal.c index 5aac2dd..0c3466f 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,17 +21,6 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO -#elif defined(__NetBSD__) -#include -#define K_ENABLE K_XLATE -#define K_DISABLE K_RAW -#define FRSIG 0 // unimplemented -#elif defined(__OpenBSD__) -#include -#include -#define K_ENABLE K_XLATE -#define K_DISABLE K_RAW -#define FRSIG SIGIO #else #error Unsupported platform #endif @@ -145,38 +134,16 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { } return 0; } -#elif defined(__NetBSD__) -static int get_tty_path(int tty, char path[static TTYPATHLEN]) { - assert(tty >= 0); - if (snprintf(path, TTYPATHLEN, "/dev/ttyE%d", tty) == -1) { - return -1; - } - return 0; -} -#elif defined(__OpenBSD__) -static int get_tty_path(int tty, char path[static TTYPATHLEN]) { - assert(tty >= 0); - if (snprintf(path, TTYPATHLEN, "/dev/ttyC%d", tty) == -1) { - return -1; - } - return 0; -} #else #error Unsupported platform #endif int terminal_open(int vt) { char path[TTYPATHLEN]; - log_debugf("terminal_open vt %d", vt); -#ifdef __OpenBSD__ - if (vt > 0) - vt--; -#endif if (get_tty_path(vt, path) == -1) { log_errorf("Could not generate tty path: %s", strerror(errno)); return -1; } - log_debugf("terminal_open path %s", path); int fd = open(path, O_RDWR | O_NOCTTY); if (fd == -1) { log_errorf("Could not open target tty: %s", strerror(errno)); @@ -186,7 +153,7 @@ int terminal_open(int vt) { } int terminal_current_vt(int fd) { -#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__linux__) struct vt_stat st; int res = ioctl(fd, VT_GETSTATE, &st); close(fd); @@ -264,20 +231,11 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("Setting KD keyboard state to %d", enable); -#ifndef __OpenBSD1__ if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { log_errorf("Could not set KD keyboard mode to %s: %s", enable ? "enabled" : "disabled", strerror(errno)); return -1; } -#else - int mode = enable ? WSKBD_RAW : WSKBD_TRANSLATED; - if (ioctl(fd, WSKBDIO_SETMODE, &mode) == -1) { - log_errorf("Could not set keyboard mode to %s: %s", - enable ? "translated" : "raw", strerror(errno)); - return -1; - } -#endif #if defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { @@ -300,19 +258,10 @@ int terminal_set_keyboard(int fd, bool enable) { int terminal_set_graphics(int fd, bool enable) { log_debugf("Setting KD graphics state to %d", enable); -#ifndef __OpenBSD1__ if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) { log_errorf("Could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", strerror(errno)); return -1; } -#else - int mode = enable ? WSDISPLAYIO_MODE_MAPPED : WSDISPLAYIO_MODE_EMUL; - if (ioctl(fd, WSDISPLAYIO_SMODE, &mode) == -1) { - log_errorf("Could not set graphics mode to %s: %s", - enable ? "mapped" : "emul", strerror(errno)); - return -1; - } -#endif return 0; } diff --git a/common/wscons.c b/common/wscons.c deleted file mode 100644 index 121074c..0000000 --- a/common/wscons.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -#if defined(__NetBSD__) -#include -#include -#endif - -#include "wscons.h" - -#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) - -#if defined(__NetBSD__) || defined(__OpenBSD__) -int path_is_wscons(const char *path) { - static const char wskbd[] = "/dev/wskbd"; - static const char wsmouse[] = "/dev/wsmouse"; - static const char wsmux[] = "/dev/wsmux"; - return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || - strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || - strncmp(path, wsmux, STRLEN(wsmouse)) == 0; -} -#else -int path_is_wscons(const char *path) { - (void)path; - return 0; -} -#endif diff --git a/include/drm.h b/include/drm.h index a8a5461..8a7fb10 100644 --- a/include/drm.h +++ b/include/drm.h @@ -5,4 +5,9 @@ int drm_set_master(int fd); int drm_drop_master(int fd); int path_is_drm(const char *path); +#if defined(__linux__) +#include +int dev_is_drm(dev_t device); +#endif + #endif diff --git a/include/evdev.h b/include/evdev.h index 5e6cfbf..6ebd943 100644 --- a/include/evdev.h +++ b/include/evdev.h @@ -4,4 +4,9 @@ int evdev_revoke(int fd); int path_is_evdev(const char *path); +#if defined(__linux__) +#include +int dev_is_evdev(dev_t device); +#endif + #endif diff --git a/include/seat.h b/include/seat.h index ff857e7..cc243b6 100644 --- a/include/seat.h +++ b/include/seat.h @@ -13,7 +13,6 @@ enum seat_device_type { SEAT_DEVICE_TYPE_NORMAL, SEAT_DEVICE_TYPE_EVDEV, SEAT_DEVICE_TYPE_DRM, - SEAT_DEVICE_TYPE_WSCONS, }; struct seat_device { diff --git a/include/wscons.h b/include/wscons.h deleted file mode 100644 index bf0c10c..0000000 --- a/include/wscons.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SEATD_WSCONS_H -#define _SEATD_WSCONS_H - -int path_is_wscons(const char *path); - -#endif diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 2589e2f..5a10c75 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -13,10 +13,10 @@ #include #include -#if defined(HAVE_LIBELOGIND) +#if defined(HAVE_ELOGIND) #include #include -#elif defined(HAVE_LIBSYSTEMD) +#elif defined(HAVE_SYSTEMD) #include #include #else @@ -28,14 +28,6 @@ #include "libseat.h" #include "log.h" -static int dev_major_is_drm(unsigned int dev_major) { - return dev_major == 226; -} - -static int dev_is_drm(dev_t device) { - return dev_major_is_drm(major(device)); -} - struct backend_logind { struct libseat base; const struct libseat_seat_listener *seat_listener; @@ -49,6 +41,7 @@ struct backend_logind { bool active; bool initial_setup; + bool awaiting_pong; int has_drm; }; @@ -77,12 +70,13 @@ static int close_seat(struct libseat *base) { static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { (void)ret_error; - (void)userdata; + struct backend_logind *session = userdata; if (sd_bus_message_is_method_error(m, NULL)) { const sd_bus_error *error = sd_bus_message_get_error(m); log_errorf("Ping failed: %s: %s", error->name, error->message); return -1; } + session->awaiting_pong = false; return 0; } @@ -97,15 +91,14 @@ static int send_ping(struct backend_logind *backend) { } static void check_pending_events(struct backend_logind *backend) { - uint64_t queued_read, queued_write; - sd_bus_get_n_queued_read(backend->bus, &queued_read); - sd_bus_get_n_queued_write(backend->bus, &queued_write); - - if (queued_read == 0 && queued_write == 0) { + if (sd_bus_get_events(backend->bus) <= 0) { + return; + } + if (backend->awaiting_pong) { return; } - // The sd_bus instance has queued data, so a dispatch is required. + // We have events pending execution, so a dispatch is required. // However, we likely already drained our socket, so there will not be // anything to read. Instead, send a ping request to logind so that the // user will be woken up by its response. @@ -114,6 +107,7 @@ static void check_pending_events(struct backend_logind *backend) { log_errorf("Could not send ping message: %s", strerror(-ret)); return; } + backend->awaiting_pong = true; } static int open_device(struct libseat *base, const char *path, int *fd) { @@ -292,7 +286,6 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { total_dispatched += dispatched; } } - check_pending_events(backend); return total_dispatched; } @@ -395,7 +388,7 @@ static int pause_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_e return 0; } - if (dev_major_is_drm(major) && strcmp(type, "gone") != 0) { + if (dev_is_drm(makedev(major, minor)) && strcmp(type, "gone") != 0) { log_debugf("DRM device paused: %s", type); assert(session->has_drm > 0); set_active(session, false); @@ -427,7 +420,7 @@ static int resume_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_ return 0; } - if (dev_major_is_drm(major)) { + if (dev_is_drm(makedev(major, minor))) { log_debug("DRM device resumed"); assert(session->has_drm > 0); set_active(session, true); @@ -749,7 +742,6 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list backend->seat_listener_data = data; backend->base.impl = &logind_impl; - check_pending_events(backend); return &backend->base; error: diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 18f26c3..7436c48 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -46,13 +46,13 @@ static int disable_seat(struct libseat *base) { static const char *seat_name(struct libseat *base) { (void)base; - return "seat0"; + return "noop"; } static int open_device(struct libseat *base, const char *path, int *fd) { (void)base; - int tmpfd = open(path, O_RDWR | O_NOCTTY | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK); + int tmpfd = open(path, O_RDWR | O_CLOEXEC); if (tmpfd < 0) { log_errorf("Failed to open device: %s", strerror(errno)); return -1; @@ -109,13 +109,12 @@ static struct libseat *noop_open_seat(const struct libseat_seat_listener *listen return NULL; } - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, backend->sockets) != 0) { + if (socketpair(AF_UNIX, SOCK_STREAM, 0, backend->sockets) != 0) { log_errorf("socketpair() failed: %s", strerror(errno)); free(backend); return NULL; } - backend->initial_setup = true; backend->seat_listener = listener; backend->seat_listener_data = data; backend->base.impl = &noop_impl; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index abcd2a5..26308d1 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -42,16 +42,32 @@ struct backend_seatd { char seat_name[MAX_SEAT_LEN]; }; +static int set_nonblock(int fd) { + int flags; + if ((flags = fcntl(fd, F_GETFD)) == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { + return -1; + } + if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + return -1; + } + return 0; +} + static int seatd_connect(void) { union { struct sockaddr_un unix; struct sockaddr generic; } addr = {{0}}; - int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { log_errorf("Could not create socket: %s", strerror(errno)); return -1; } + if (set_nonblock(fd) == -1) { + log_errorf("Could not make socket non-blocking: %s", strerror(errno)); + close(fd); + return -1; + } const char *path = getenv("SEATD_SOCK"); if (path == NULL) { path = SEATD_DEFAULTPATH; @@ -600,10 +616,29 @@ const struct seat_impl seatd_impl = { }; #ifdef BUILTIN_ENABLED +#include + +static int set_deathsig(int signal); + +#if defined(__linux__) +#include + +static int set_deathsig(int signal) { + return prctl(PR_SET_PDEATHSIG, signal); +} +#elif defined(__FreeBSD__) +#include + +static int set_deathsig(int signal) { + return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signal); +} +#else +#error Unsupported platform +#endif static struct libseat *builtin_open_seat(const struct libseat_seat_listener *listener, void *data) { int fds[2]; - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) == -1) { + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) { log_errorf("Could not create socket pair: %s", strerror(errno)); return NULL; } @@ -615,7 +650,6 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis close(fds[1]); return NULL; } else if (pid == 0) { - close(fds[1]); int fd = fds[0]; int res = 0; struct server server = {0}; @@ -630,7 +664,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis res = 1; goto server_error; } - log_info("Started embedded seatd"); + set_deathsig(SIGTERM); while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("Could not poll server socket: %s", strerror(errno)); @@ -642,10 +676,8 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis server_finish(&server); error: close(fd); - log_info("Stopped embedded seatd"); exit(res); } else { - close(fds[0]); int fd = fds[1]; return _open_seat(listener, data, fd); } diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index 73d302d..9234203 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -10,13 +10,12 @@ seatd-launch - Start a process with its own seatd instance # OPTIONS -*-l * - Log-level to pass to seatd. See *seatd*(1) for information about - available log-levels. - *-h* Show help message and quit. +*-s * + Where to create the seatd socket. Defaults to a unique file path. + *-v* Show the version number and quit. diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 92f8e4b..de95843 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -13,7 +13,7 @@ seatd - A seat management daemon *-h* Show help message and quit. -*-n * +*-n* FD to notify readiness on. A single newline will be written and the fd closed when seatd is ready to serve requests. This is compatible with s6's notification protocol. @@ -24,9 +24,8 @@ seatd - A seat management daemon *-g * Group to own the seatd socket. -*-l * - Log-level to use. Must be one of debug, info, error or silent. Defaults - to error. +*-s * + Where to create the seatd socket. Defaults to `/run/seatd.sock`. *-v* Show the version number and quit. @@ -39,12 +38,17 @@ such as displays and input devices in a multi-session, multi-seat environment. seatd operates over a UNIX domain socket, with *libseat* providing the client-side of the protocol. -The location of the socket for seatd is set at compile-time. - # ENVIRONMENT -*SEATD_VTBOUND* - If set to "0", the seat will not be bound to a VT. +[[ *VARIABLE* +:[ *VALUES* +:< *DESCRIPTION* +| SEATD_SOCK +: File path +: Informs libseat of the socket location, needed if it differs from `/run/seatd.sock` +| SEATD_LOGLEVEL +: silent, error, info, debug +: Sets the seatd log level. Defaults to "error" # SEE ALSO diff --git a/meson.build b/meson.build index fcd85de..d8fd25d 100644 --- a/meson.build +++ b/meson.build @@ -1,9 +1,9 @@ project( 'seatd', 'c', - version: '0.8.0', + version: '0.6.3', license: 'MIT', - meson_version: '>=0.60.0', + meson_version: '>=0.56.0', default_options: [ 'c_std=c11', 'warning_level=3', @@ -22,22 +22,9 @@ if defaultpath == '' endif endif -seatdpath = get_option('prefix') / get_option('bindir') / 'seatd' +seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir')) cc = meson.get_compiler('c') - -add_project_arguments( - [ - '-D_XOPEN_SOURCE=700', - '-D_BSD_SOURCE', - '-D_NETBSD_SOURCE', - '-DSEATD_VERSION="@0@"'.format(meson.project_version()), - '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), - '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), - ], - language: 'c', -) - add_project_arguments(cc.get_supported_arguments( [ '-Wundef', @@ -52,13 +39,12 @@ add_project_arguments(cc.get_supported_arguments( '-Wno-unknown-warning-option', '-Wno-unused-command-line-argument', '-Wvla', - ]), - language: 'c', -) - -add_project_arguments(cc.get_supported_link_arguments( - [ '-Wl,--exclude-libs=ALL', + '-D_XOPEN_SOURCE=700', + '-D__BSD_VISIBLE', + '-DSEATD_VERSION="@0@"'.format(meson.project_version()), + '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), + '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), ]), language: 'c', ) @@ -73,7 +59,7 @@ endif # Hacks source_root = meson.current_source_dir().split('/') -build_root = meson.global_build_root().split('/') +build_root = meson.build_root().split('/') relative_dir_parts = [] i = 0 in_prefix = true @@ -114,7 +100,6 @@ server_files = [ 'common/connection.c', 'common/evdev.c', 'common/drm.c', - 'common/wscons.c', 'seatd/poller.c', 'seatd/seat.c', 'seatd/client.c', @@ -129,26 +114,31 @@ if with_seatd or with_builtin private_files += 'libseat/backend/seatd.c' endif -libseat_c_args = ['-DLIBSEAT=1'] - if with_seatd - libseat_c_args += '-DSEATD_ENABLED=1' + add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif logind = disabler() +logind_provider = '' if get_option('libseat-logind') != 'disabled' if get_option('libseat-logind') == 'auto' and get_option('auto_features').disabled() # Disable logind elif get_option('libseat-logind') == 'auto' assert(get_option('auto_features').auto(), '-Dlibseat-logind must be set to systemd or elogind since auto_features != auto') - logind = dependency(['libelogind', 'libsystemd'], required: false) + foreach logind_provider : ['elogind', 'systemd'] + logind = dependency('lib@0@'.format(logind_provider), required: false) + if logind.found() + break + endif + endforeach else - logind = dependency('lib@0@'.format(get_option('libseat-logind'))) + logind_provider = get_option('libseat-logind') + logind = dependency('lib@0@'.format(logind_provider)) endif if logind.found() - libseat_c_args += '-DLOGIND_ENABLED=1' - libseat_c_args += '-DHAVE_@0@=1'.format(logind.name().to_upper()) + add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') + add_project_arguments('-DHAVE_@0@=1'.format(logind_provider.to_upper()), language: 'c') private_files += [ 'libseat/backend/logind.c', 'common/drm.c', @@ -158,11 +148,11 @@ if get_option('libseat-logind') != 'disabled' endif # needed for cross-compilation -# realtime = meson.get_compiler('c').find_library('rt') -# private_deps += realtime +realtime = meson.get_compiler('c').find_library('rt') +private_deps += realtime if with_builtin - libseat_c_args += '-DBUILTIN_ENABLED=1' + add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c') private_files += server_files endif @@ -171,7 +161,6 @@ private_lib = static_library( private_files, dependencies: private_deps, include_directories: [include_directories('.', 'include')], - c_args: libseat_c_args, ) symbols_file = 'libseat/libseat.syms' @@ -179,13 +168,12 @@ symbols_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), lib = library( 'seat', # This results in the library being called 'libseat' [ 'libseat/libseat.c', 'libseat/backend/noop.c' ], - soversion: '@0@'.format(libseat_soversion), + soversion: libseat_soversion, link_with: private_lib, include_directories: [include_directories('.', 'include')], install: true, link_args: symbols_flag, link_depends: symbols_file, - c_args: libseat_c_args, ) install_headers('include/libseat.h') @@ -212,22 +200,20 @@ libseat = declare_dependency( variables: libseat_vars, ) -meson.override_dependency('libseat', libseat) - if with_server executable( 'seatd', [ server_files, 'seatd/seatd.c' ], include_directories: [include_directories('.', 'include')], install: true, -# dependencies: [realtime], + dependencies: [realtime], ) executable( 'seatd-launch', [ 'seatd-launch/seatd-launch.c' ], include_directories: [include_directories('.', 'include')], install: true, -# dependencies: [realtime], + dependencies: [realtime], ) endif @@ -261,6 +247,7 @@ else endif if scdoc.found() + scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) mandir = get_option('mandir') foreach src : ['seatd.1.scd', 'seatd-launch.1.scd'] @@ -272,9 +259,9 @@ if scdoc.found() output, input: 'man/' + src, output: output, - command: scdoc.get_variable(pkgconfig: 'scdoc'), - feed: true, - capture: true, + command: [ + 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.full_path(), output) + ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) ) @@ -284,7 +271,7 @@ endif summary({ 'libseat-seatd': with_seatd, 'libseat-builtin': with_builtin, - 'libseat-systemd': logind.found() and logind.name() == 'libsystemd', - 'libseat-elogind': logind.found() and logind.name() == 'libelogind', + 'libseat-systemd': logind.found() and logind_provider == 'systemd', + 'libseat-elogind': logind.found() and logind_provider == 'elogind', 'server': with_server, }, bool_yn: true) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 65d4f33..69ca86a 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -11,20 +11,21 @@ #include int main(int argc, char *argv[]) { + (void)argc; + const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" - " -l Log-level to pass to seatd\n" " -h Show this help message\n" + " -s Where to create the seatd socket\n" " -v Show the version number\n" "\n"; int c; - char loglevel[16] = "info"; - while ((c = getopt(argc, argv, "vhl:")) != -1) { + char *sockpath = NULL; + while ((c = getopt(argc, argv, "vhs:")) != -1) { switch (c) { - case 'l': - strncpy(loglevel, optarg, sizeof loglevel); - loglevel[sizeof loglevel - 1] = '\0'; + case 's': + sockpath = optarg; break; case 'v': printf("seatd-launch version %s\n", SEATD_VERSION); @@ -33,7 +34,7 @@ int main(int argc, char *argv[]) { printf("%s", usage); return 0; case '?': - fprintf(stderr, "Try 'seatd-launch -h' for more information.\n"); + fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); return 1; default: abort(); @@ -46,30 +47,44 @@ int main(int argc, char *argv[]) { } char **command = &argv[optind]; - int readiness_pipe[2]; - if (pipe(readiness_pipe) == -1) { + char sockbuf[256]; + if (sockpath == NULL) { + sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); + sockpath = sockbuf; + } + + unlink(sockpath); + + int fds[2]; + if (pipe(fds) == -1) { perror("Could not create pipe"); goto error; } - // Start seatd pid_t seatd_child = fork(); if (seatd_child == -1) { perror("Could not fork seatd process"); goto error; } else if (seatd_child == 0) { - close(readiness_pipe[0]); + close(fds[0]); char pipebuf[16] = {0}; - snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]); + snprintf(pipebuf, sizeof pipebuf, "%d", fds[1]); - char *env[1] = {NULL}; - char *command[] = {"seatd", "-n", pipebuf, "-l", loglevel, "-z", NULL}; + char *env[2] = {NULL, NULL}; + char loglevelbuf[32] = {0}; + char *cur_loglevel = getenv("SEATD_LOGLEVEL"); + if (cur_loglevel != NULL) { + snprintf(loglevelbuf, sizeof loglevelbuf, "SEATD_LOGLEVEL=%s", cur_loglevel); + env[0] = loglevelbuf; + } + + char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, NULL}; execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); } - close(readiness_pipe[1]); + close(fds[1]); // Wait for seatd to be ready char buf[1] = {0}; @@ -84,7 +99,7 @@ int main(int argc, char *argv[]) { } struct pollfd fd = { - .fd = readiness_pipe[0], + .fd = fds[0], .events = POLLIN, }; @@ -99,7 +114,7 @@ int main(int argc, char *argv[]) { } if (fd.revents & POLLIN) { - ssize_t n = read(readiness_pipe[0], buf, 1); + ssize_t n = read(fds[0], buf, 1); if (n == -1 && errno != EINTR) { perror("Could not read from pipe"); goto error_seatd; @@ -108,17 +123,17 @@ int main(int argc, char *argv[]) { } } } - close(readiness_pipe[0]); + close(fds[0]); uid_t uid = getuid(); gid_t gid = getgid(); // Restrict access to the socket to just us - if (chown(SEATD_DEFAULTPATH, uid, gid) == -1) { + if (chown(sockpath, uid, gid) == -1) { perror("Could not chown seatd socket"); goto error_seatd; } - if (chmod(SEATD_DEFAULTPATH, 0700) == -1) { + if (chmod(sockpath, 0700) == -1) { perror("Could not chmod socket"); goto error_seatd; } @@ -138,7 +153,7 @@ int main(int argc, char *argv[]) { perror("Could not fork target process"); goto error_seatd; } else if (child == 0) { - setenv("SEATD_SOCK", SEATD_DEFAULTPATH, 1); + setenv("SEATD_SOCK", sockpath, 1); execvp(command[0], command); perror("Could not start target"); _exit(1); @@ -155,6 +170,9 @@ int main(int argc, char *argv[]) { } } + if (unlink(sockpath) != 0) { + perror("Could not unlink socket"); + } if (kill(seatd_child, SIGTERM) != 0) { perror("Could not kill seatd"); } @@ -168,6 +186,7 @@ int main(int argc, char *argv[]) { } error_seatd: + unlink(sockpath); kill(seatd_child, SIGTERM); error: return 1; diff --git a/seatd/client.c b/seatd/client.c index 481704e..220c5d3 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -14,10 +14,6 @@ #include #endif -#if defined(__NetBSD__) -#include -#endif - #include "client.h" #include "linked_list.h" #include "log.h" @@ -38,40 +34,6 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { *uid = cred.uid; *gid = cred.gid; return 0; -#elif defined(__NetBSD__) - struct unpcbid cred; - socklen_t len = sizeof cred; - if (getsockopt(fd, 0, LOCAL_PEEREID, &cred, &len) == -1) { - // assume builtin backend - if (errno == EINVAL) { - *pid = getpid(); - *uid = getuid(); - *gid = getgid(); - return 0; - } - return -1; - } - *pid = cred.unp_pid; - *uid = cred.unp_euid; - *gid = cred.unp_egid; - return 0; -#elif defined(__OpenBSD__) - struct sockpeercred peercred; - socklen_t len = sizeof(peercred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &len) == -1) { - // assume builtin backend - if (errno == EINVAL) { - *pid = getpid(); - *uid = getuid(); - *gid = getgid(); - return 0; - } - return -1; - } - *pid = peercred.pid; - *uid = peercred.uid; - *gid = peercred.gid; - return 0; #elif defined(__FreeBSD__) struct xucred cred; socklen_t len = sizeof cred; @@ -87,7 +49,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { *gid = cred.cr_ngroups > 0 ? cred.cr_groups[0] : (gid_t)-1; return 0; #else -#error Unsupported platform + return -1; #endif } @@ -119,13 +81,6 @@ struct client *client_create(struct server *server, int client_fd) { void client_destroy(struct client *client) { assert(client); - -#ifdef LIBSEAT - // The built-in backend version of seatd should terminate once its only - // client disconnects. - client->server->running = false; -#endif - client->server = NULL; if (client->connection.fd != -1) { close(client->connection.fd); @@ -327,7 +282,7 @@ static int handle_switch_session(struct client *client, int session) { log_error("Protocol error: no seat associated with client"); return -1; } - log_debugf("handle_switch_session %d", session); + if (seat_set_next_session(client, session) == -1) { goto error; } @@ -370,7 +325,6 @@ static int handle_ping(struct client *client) { static int client_handle_opcode(struct client *client, uint16_t opcode, size_t size) { int res = 0; - log_debugf("client_handle_opcode: %d\n", opcode); switch (opcode) { case CLIENT_OPEN_SEAT: { if (size != 0) { @@ -507,13 +461,7 @@ int client_handle_connection(int fd, uint32_t mask, void *data) { goto fail; } if (len == 0) { -// https://man.netbsd.org/poll.2 -// Sockets produce POLLIN rather than POLLHUP when the remote end is closed. -#if defined(__NetBSD__) - log_info("Client disconnected"); -#else log_error("Could not read client connection: zero-length read"); -#endif goto fail; } diff --git a/seatd/seat.c b/seatd/seat.c index 8820992..354273f 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -17,7 +17,6 @@ #include "protocol.h" #include "seat.h" #include "terminal.h" -#include "wscons.h" static int seat_close_client(struct client *client); static int vt_close(int vt); @@ -87,8 +86,8 @@ static int vt_close(int vt) { return -1; } terminal_set_process_switching(ttyfd, true); - terminal_set_graphics(ttyfd, false); terminal_set_keyboard(ttyfd, true); + terminal_set_graphics(ttyfd, false); close(ttyfd); return 0; } @@ -107,7 +106,6 @@ static int vt_switch(struct seat *seat, int vt) { static int vt_ack(struct seat *seat, bool release) { int tty0fd = terminal_open(seat->cur_vt); - log_debugf("vt_ack VT %d %d\n", seat->cur_vt, release); if (tty0fd == -1) { log_errorf("Could not open tty0 to ack VT signal: %s", strerror(errno)); return -1; @@ -237,8 +235,6 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { type = SEAT_DEVICE_TYPE_EVDEV; } else if (path_is_drm(sanitized_path)) { type = SEAT_DEVICE_TYPE_DRM; - } else if (path_is_wscons(sanitized_path)) { - type = SEAT_DEVICE_TYPE_WSCONS; } else { log_errorf("%s is not a supported device type ", sanitized_path); errno = ENOENT; @@ -285,9 +281,6 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { case SEAT_DEVICE_TYPE_EVDEV: // Nothing to do here break; - case SEAT_DEVICE_TYPE_WSCONS: - // Nothing to do here - break; default: log_error("Invalid seat device type"); abort(); @@ -340,9 +333,6 @@ static int seat_deactivate_device(struct seat_device *seat_device) { return -1; } break; - case SEAT_DEVICE_TYPE_WSCONS: - // Nothing to do here - break; default: log_error("Invalid seat device type"); abort(); @@ -392,9 +382,6 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ case SEAT_DEVICE_TYPE_EVDEV: errno = EINVAL; return -1; - case SEAT_DEVICE_TYPE_WSCONS: - // Nothing to do here - break; default: log_error("Invalid seat device type"); abort(); @@ -538,7 +525,7 @@ static int seat_disable_client(struct client *client) { errno = EBUSY; return -1; } - assert(seat->active_client == client); + assert(seat->active_client = client); // We *deactivate* all remaining fds. These may later be reactivated. // The reason we cannot just close them is that certain device fds, such diff --git a/seatd/seatd.c b/seatd/seatd.c index f88e6c9..053d44b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -40,15 +40,15 @@ static int open_socket(const char *path, int uid, int gid) { goto error; } if (uid != -1 || gid != -1) { - if (chmod(path, 0770) == -1) { - log_errorf("Could not chmod socket: %s", strerror(errno)); - goto error; - } if (chown(path, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); goto error; } + if (chmod(path, 0770) == -1) { + log_errorf("Could not chmod socket: %s", strerror(errno)); + goto error; + } } return fd; error: @@ -57,23 +57,35 @@ error: } int main(int argc, char *argv[]) { + char *loglevel = getenv("SEATD_LOGLEVEL"); + enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; + if (loglevel != NULL) { + if (strcmp(loglevel, "silent") == 0) { + level = LIBSEAT_LOG_LEVEL_SILENT; + } else if (strcmp(loglevel, "info") == 0) { + level = LIBSEAT_LOG_LEVEL_INFO; + } else if (strcmp(loglevel, "debug") == 0) { + level = LIBSEAT_LOG_LEVEL_DEBUG; + } + } + log_init(); + libseat_set_log_level(level); + const char *usage = "Usage: seatd [options]\n" "\n" " -h Show this help message\n" - " -n FD to notify readiness on\n" + " -n FD to notify readiness on\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" - " -l Log-level, one of debug, info, error or silent\n" + " -s Where to create the seatd socket\n" " -v Show the version number\n" "\n"; int c; int uid = -1, gid = -1; int readiness = -1; - bool unlink_existing_socket = true; - bool chown_socket = true; - enum libseat_log_level level = LIBSEAT_LOG_LEVEL_INFO; - while ((c = getopt(argc, argv, "vhn:g:u:l:z")) != -1) { + const char *socket_path = getenv("SEATD_SOCK"); + while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { switch (c) { case 'n': readiness = atoi(optarg); @@ -82,11 +94,10 @@ int main(int argc, char *argv[]) { return 1; } break; + case 's': + socket_path = optarg; + break; case 'u': { - if (!chown_socket) { - fprintf(stderr, "-u/-g and -z are mutually exclusive\n"); - return 1; - } struct passwd *pw = getpwnam(optarg); if (pw == NULL) { fprintf(stderr, "Could not find user by name '%s'.\n", optarg); @@ -97,10 +108,6 @@ int main(int argc, char *argv[]) { break; } case 'g': { - if (!chown_socket) { - fprintf(stderr, "-u/-g and -z are mutually exclusive\n"); - return 1; - } struct group *gr = getgrnam(optarg); if (gr == NULL) { fprintf(stderr, "Could not find group by name '%s'.\n", optarg); @@ -110,31 +117,6 @@ int main(int argc, char *argv[]) { } break; } - case 'l': - if (strcmp(optarg, "debug") == 0) { - level = LIBSEAT_LOG_LEVEL_DEBUG; - } else if (strcmp(optarg, "info") == 0) { - level = LIBSEAT_LOG_LEVEL_INFO; - } else if (strcmp(optarg, "error") == 0) { - level = LIBSEAT_LOG_LEVEL_ERROR; - } else if (strcmp(optarg, "silent") == 0) { - level = LIBSEAT_LOG_LEVEL_SILENT; - } else { - fprintf(stderr, "Invalid loglevel: %s\n", optarg); - return 1; - } - break; - case 'z': - // Running under seatd-launch. We do not unlink files - // to protect against multiple instances, and - // seatd-launch takes care of ownership. - if (uid != -1 || gid != -1) { - fprintf(stderr, "-u/-g and -z are mutually exclusive\n"); - return 1; - } - unlink_existing_socket = false; - chown_socket = false; - break; case 'v': printf("seatd version %s\n", SEATD_VERSION); return 0; @@ -149,46 +131,33 @@ int main(int argc, char *argv[]) { } } - log_init(); - libseat_set_log_level(level); - - struct stat st; - if (lstat(SEATD_DEFAULTPATH, &st) == 0) { - if (!S_ISSOCK(st.st_mode)) { - log_errorf("Non-socket file found at socket path %s, refusing to start", - SEATD_DEFAULTPATH); - return 1; - } else if (!unlink_existing_socket) { - log_errorf("Socket file found at socket path %s, refusing to start", - SEATD_DEFAULTPATH); - return 1; - } else { - // We only do this if the socket path is not user specified - log_infof("Removing leftover socket at %s", SEATD_DEFAULTPATH); - if (unlink(SEATD_DEFAULTPATH) == -1) { - log_errorf("Could not remove leftover socket: %s", strerror(errno)); - return 1; - } + if (socket_path == NULL) { + socket_path = SEATD_DEFAULTPATH; + struct stat st; + if (stat(socket_path, &st) == 0) { + log_info("Removing leftover seatd socket"); + unlink(socket_path); } } struct server server = {0}; if (server_init(&server) == -1) { - log_errorf("server_init failed: %s", strerror(errno)); + log_errorf("server_create failed: %s", strerror(errno)); return 1; } - int ret = 1; - int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid); + int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { log_error("Could not create server socket"); - goto error_server; + server_finish(&server); + return 1; } if (poller_add_fd(&server.poller, socket_fd, EVENT_READABLE, server_handle_connection, &server) == NULL) { log_errorf("Could not add socket to poller: %s", strerror(errno)); close(socket_fd); - goto error_socket; + server_finish(&server); + return 1; } log_info("seatd started"); @@ -203,18 +172,12 @@ int main(int argc, char *argv[]) { while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("Poller failed: %s", strerror(errno)); - goto error_socket; + return 1; } } - ret = 0; - -error_socket: - if (unlink(SEATD_DEFAULTPATH) == -1) { - log_errorf("Could not remove socket: %s", strerror(errno)); - } -error_server: server_finish(&server); + unlink(socket_path); log_info("seatd stopped"); - return ret; + return 0; } diff --git a/seatd/server.c b/seatd/server.c index 47d6e91..0a08f50 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -123,18 +123,12 @@ static int set_nonblock(int fd) { int server_add_client(struct server *server, int fd) { if (set_nonblock(fd) != 0) { - log_errorf("Could not prepare new client socket: %s", strerror(errno)); close(fd); + log_errorf("Could not prepare new client socket: %s", strerror(errno)); return -1; } struct client *client = client_create(server, fd); - if (client == NULL) { - log_errorf("Could not create client: %s", strerror(errno)); - close(fd); - return -1; - } - client->event_source = poller_add_fd(&server->poller, fd, EVENT_READABLE, client_handle_connection, client); if (client->event_source == NULL) { @@ -152,7 +146,7 @@ int server_handle_connection(int fd, uint32_t mask, void *data) { if (mask & (EVENT_ERROR | EVENT_HANGUP)) { shutdown(fd, SHUT_RDWR); server->running = false; - log_error("Server socket received an error"); + log_errorf("Server socket received an error: %s", strerror(errno)); return -1; } diff --git a/tests/poller.c b/tests/poller.c index dd36c7d..382d9d2 100644 --- a/tests/poller.c +++ b/tests/poller.c @@ -123,10 +123,6 @@ static int test_signal_event(int signal, void *data) { return 0; } -#ifdef __OpenBSD__ -#define SIGRTMIN SIGUSR1 -#endif - static void test_poller_single_signal(void) { struct poller poller; test_assert(poller_init(&poller) == 0);