Compare commits

..

No commits in common. "obsd" and "0.6.3" have entirely different histories.
obsd ... 0.6.3

25 changed files with 226 additions and 406 deletions

View file

@ -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: |

View file

@ -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: |

View file

@ -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

View file

@ -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

View file

@ -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).

View file

@ -2,6 +2,10 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#if defined(__linux__)
#include <sys/sysmacros.h>
#endif
#include "drm.h"
// From libdrm
@ -11,7 +15,6 @@
#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)
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

View file

@ -9,13 +9,14 @@
#include <sys/sysmacros.h>
#elif defined(__FreeBSD__)
#include <dev/evdev/input.h>
#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

View file

@ -21,17 +21,6 @@
#define K_ENABLE K_XLATE
#define K_DISABLE K_RAW
#define FRSIG SIGIO
#elif defined(__NetBSD__)
#include <dev/wscons/wsdisplay_usl_io.h>
#define K_ENABLE K_XLATE
#define K_DISABLE K_RAW
#define FRSIG 0 // unimplemented
#elif defined(__OpenBSD__)
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplay_usl_io.h>
#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;
}

View file

@ -1,27 +0,0 @@
#include <stdlib.h>
#include <string.h>
#if defined(__NetBSD__)
#include <stdlib.h>
#include <sys/stat.h>
#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

View file

@ -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 <sys/types.h>
int dev_is_drm(dev_t device);
#endif
#endif

View file

@ -4,4 +4,9 @@
int evdev_revoke(int fd);
int path_is_evdev(const char *path);
#if defined(__linux__)
#include <sys/types.h>
int dev_is_evdev(dev_t device);
#endif
#endif

View file

@ -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 {

View file

@ -1,6 +0,0 @@
#ifndef _SEATD_WSCONS_H
#define _SEATD_WSCONS_H
int path_is_wscons(const char *path);
#endif

View file

@ -13,10 +13,10 @@
#include <sys/un.h>
#include <unistd.h>
#if defined(HAVE_LIBELOGIND)
#if defined(HAVE_ELOGIND)
#include <elogind/sd-bus.h>
#include <elogind/sd-login.h>
#elif defined(HAVE_LIBSYSTEMD)
#elif defined(HAVE_SYSTEMD)
#include <systemd/sd-bus.h>
#include <systemd/sd-login.h>
#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:

View file

@ -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;

View file

@ -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 <signal.h>
static int set_deathsig(int signal);
#if defined(__linux__)
#include <sys/prctl.h>
static int set_deathsig(int signal) {
return prctl(PR_SET_PDEATHSIG, signal);
}
#elif defined(__FreeBSD__)
#include <sys/procctl.h>
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);
}

View file

@ -10,13 +10,12 @@ seatd-launch - Start a process with its own seatd instance
# OPTIONS
*-l <loglevel>*
Log-level to pass to seatd. See *seatd*(1) for information about
available log-levels.
*-h*
Show help message and quit.
*-s <path>*
Where to create the seatd socket. Defaults to a unique file path.
*-v*
Show the version number and quit.

View file

@ -13,7 +13,7 @@ seatd - A seat management daemon
*-h*
Show help message and quit.
*-n <fd>*
*-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>*
Group to own the seatd socket.
*-l <loglevel>*
Log-level to use. Must be one of debug, info, error or silent. Defaults
to error.
*-s <path>*
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

View file

@ -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)

View file

@ -11,20 +11,21 @@
#include <unistd.h>
int main(int argc, char *argv[]) {
(void)argc;
const char *usage = "Usage: seatd-launch [options] [--] command\n"
"\n"
" -l <loglevel> Log-level to pass to seatd\n"
" -h Show this help message\n"
" -s <path> 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;

View file

@ -14,10 +14,6 @@
#include <sys/un.h>
#endif
#if defined(__NetBSD__)
#include <sys/un.h>
#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;
}

View file

@ -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

View file

@ -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> FD to notify readiness on\n"
" -u <user> User to own the seatd socket\n"
" -g <group> Group to own the seatd socket\n"
" -l <loglevel> Log-level, one of debug, info, error or silent\n"
" -s <path> 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);
if (socket_path == NULL) {
socket_path = SEATD_DEFAULTPATH;
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 (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;
}

View file

@ -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;
}

View file

@ -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);