Compare commits

...

53 commits
0.6.4 ... obsd

Author SHA1 Message Date
b4462cb033 attempt to support VT switches on OpenBSD 2024-07-10 15:19:41 +02:00
cc09e26976 Merge remote-tracking branch 'origin/master' into obsd 2023-11-08 12:00:16 +01:00
Adrien Demarez
0746edbeae seatd: fix small bug in assert 2023-10-24 11:59:51 +02:00
Kenny Levinsen
3e9ef69f14 Bump version to 0.8.0 2023-07-19 11:18:33 +02:00
a8aee6fa70 Add basic OpenBSD support
XXX more work needed to manage VT switches and proper
XXX fbtab(4) support to allow for non-root users
2023-07-05 16:57:27 +02:00
4b2ecdf936 Add basic OpenBSD support
XXX more work needed to manage VT switches and proper
XXX fbtab(4) support to allow for non-root users
2023-07-05 10:49:24 +02:00
f2ff233c26 No -lrt on OpenBSD
XXX This is crude, should add meson tests
2023-07-05 10:48:14 +02:00
dbaa859f28 define _BSD_SOURCE rather then __BSD_VISIBLE
__BSD_VISIBLE was set to 0, causing issues on OpenBSD
The proper way is to set _BSD_SOURCE
2023-07-05 10:47:06 +02:00
Jessica Clarke
1bd042e5b0 drm: Support drm-subtree drivers on FreeBSD
The drm-kmod drivers use linuxkpi and end up with /dev/drm being the
canonical path for the devices, but the drm-subtree drivers use drmkpi
which has them appear under /dev/dri like Linux. Thus, adapt path_is_drm
to recognise both on FreeBSD.
2023-05-24 16:43:21 +02:00
Anna (navi) Figueiredo Gomes
56720a6275 noop: Additional open flags for open(2)
Matching the functionallity by the seatd open call. O_NONBLOCK is
specially important for libseat, otherwise it hangs while trying to
drain all events from an input device fd.

Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
2023-04-01 15:34:53 +02:00
Anna (navi) Figueiredo Gomes
e5b018def8 noop: Return seat0 as the seat name
wlroots' libinput backend expects the name of the seat to either match
ID_SEAT from udev, or in case ID_SEAT returns nothing, match seat0. As
noop has no seat switching, always returning seat0 as the session name
fixes that.

Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
2023-04-01 15:34:53 +02:00
Alyssa Ross
3e0d510b2c meson: fix seatdpath with absolute bindir
Quoting the Meson documentation:

> Note that the value returned for built-in options that end in `dir`
> such as `bindir` and `libdir` is usually a path relative to (and
> inside) the `prefix` but you should not rely on that, as it can also
> be an absolute path [in some cases](Builtin-options.md#universal-options).
> [`install_dir` arguments](Installing.md) handle that as expected
> but if you need an absolute path, e.g. to use in a define etc.,
> you should use the path concatenation operator like this:
> `get_option('prefix') / get_option('localstatedir')`.
> Never manually join paths as if they were strings.

The concatenation of two absolute paths caused seatd-launch in Nixpkgs
to try to launch e.g.
/nix/store/43wyk9s2l2z8cparnshbf24d39vm5272-seatd-0.7.0//nix/store/j9a7k4qqwc3byyfmpqwg46shmh6g82yf-seatd-0.7.0-bin/bin/seatd.
2023-03-13 17:06:31 +01:00
Simon Ser
207e2a5936 man: add missing arg in -n syntax 2023-01-28 23:10:29 +01:00
Chia-I Wu
9b8b6e0bf8 noop: initialize initial_setup
Otherwise the enable_seat callback is never called.
2023-01-16 13:13:52 +01:00
Simon Ser
14355639f8 man: document SEATD_VTBOUND 2022-11-30 18:38:50 +01:00
Kenny Levinsen
a803ba0502 seatd-launch: Avoid argv[0] in help text 2022-05-23 22:03:38 +02:00
Kenny Levinsen
6888653a8d wscons: Fix STRLEN 2022-03-30 00:39:35 +02:00
Simon Ser
2842f0e2b1 seatd: refuse to compile with missing get_peer impl
Instead of using a stub, error out when get_peer isn't implemented
for the target platform. client_create relies on it.
2022-03-29 20:08:00 +02:00
Simon Ser
85d0bf5943 seatd: handle client_create failure
Failure to create the client causes a null pointer dereference.
2022-03-29 20:07:47 +02:00
Kenny Levinsen
8f8c9558e6 drm: Make dev_is_drm local to logind backend
This function is only used for logind, which is Linux-specific, but the
presence in common/drm.c suggested that it had to be portable.

Move it to the logind backend for now.
2022-03-29 10:54:27 +02:00
Kenny Levinsen
0462e9331d wscons: Move to its own device type
This reduces ifdefs and avoids overloading evdev as something it is not.
2022-03-29 10:54:27 +02:00
Kenny Levinsen
684dd61945 terminal: Revert FreeBSD behavior in set_keyboard
4ad48cb305 introduced support for NetBSD,
which modified a number of our ifdefs. In that process, FreeBSD was
accidentally excluded from an important code path that controls keyboard
usage on the kernel console.

Revert part of that change to restore FreeBSD behavior.
2022-03-29 10:03:30 +02:00
Kenny Levinsen
d5539dead8 meson: library soversion arg should be string
muon, a meson implementation in C, is more strict with its types and
revealed this discrepancy between meson behavior and documentation.
2022-03-28 16:28:00 +02:00
Kenny Levinsen
845256009b readme: Mention NetBSD 2022-03-23 20:29:09 +01:00
illiliti
a5f9a2a2c8 ci: Add NetBSD 2022-03-16 21:39:46 +01:00
illiliti
4ad48cb305 Initial netbsd support 2022-03-16 21:39:46 +01:00
Kenny Levinsen
1990f9b034 ci: Set loglevel argument to debug 2022-03-16 21:27:05 +01:00
Kenny Levinsen
bb0efb65b3 Bump version to 0.7.0 2022-03-03 17:52:50 +01:00
Kenny Levinsen
ce6a6b7d2e meson: Fix meson warnings 2022-03-03 17:52:26 +01:00
Kenny Levinsen
8dc6a50d88 builtin: Remove deathsig and log start/stop
Proper handling of client disconnect mean that we no longer need
deathsig handling.
2022-03-03 17:52:21 +01:00
Kenny Levinsen
795cf169e7 seatd: Shut down on client disconnect in builtin
If we're part of the libseat builtin backend, then we only have one
client. Shut down the server when this client disconnects.
2022-03-03 14:44:56 +01:00
Kenny Levinsen
46c83972fe builtin: Close other end of socketpair after fork
We will not get a socket hangup if we have duplicates socket fds in the
parent or child, so make sure we clean this up properly after fork.
2022-03-03 14:44:49 +01:00
Kenny Levinsen
abcecbb53b meson: Only set libseat defines for libseat itself
This allows us to distinguish between when we build seatd as part of the
builtin libseat backend, or when we build seatd on its own.
2022-03-03 14:40:40 +01:00
Kenny Levinsen
ae42d05513 seatd: Change default log-level to info 2022-02-26 22:56:42 +01:00
Kenny Levinsen
0d6bdf4f01 seatd: Remove runtime socket path configuration
Configurable socket paths exist mainly to facilitate multiple parallel
seatd instances. However, the only valid use-case for running multiple
instances of seatd is testing during development, which can just as well
be done by changing SEATD_DEFAULTPATH at compile-time for test builds.

Remove the command-line argument in seatd for runtime configuration of
socket path, hardcode the socket path in seatd-launch, and change seatd
unlink/chmod/chown code to not run when started by seatd-launch.

This means that seatd-launch will now fail to start seatd if another
seatd instance is already running. The unlink code still runs when seatd
is started normally to assist in system crash recovery, but this may be
removed later if we deem it unnecessary.
2022-02-26 22:25:27 +01:00
Kenny Levinsen
466efea49b seatd: Handle socket unlink errors
This ensures early failure and better error messages.
2022-02-26 19:37:49 +01:00
Kenny Levinsen
9bbdf0f0b8 seatd: Command-line argument for loglevel
SEATD_LOGLEVEL was used to set the loglevel despite already having
getopt in place. Remove the environment variable and make a command-line
argument for it instead.
2022-02-26 19:17:26 +01:00
Kenny Levinsen
3eb0db57bb seatd-launch: Minor readability improvements 2022-02-21 21:33:06 +01:00
Kenny Levinsen
ed90ed62cd seatd-launch: Use snprintf for socket path
We also reduce the size of the buffer from 256 bytes to a much more
reasonable 32 bytes.
2022-02-21 21:27:14 +01:00
Kenny Levinsen
a44476ce65 seatd: Fix usage rendering 2022-02-21 12:04:09 +01:00
Kenny Levinsen
10658dc543 seatd-launch: Remove socket path command line arg
This should not need to be configured, so remove the argument. If
downstream prefers a different folder, the location can be made
compile-time configurable like for seatd itself.
2022-02-21 12:02:31 +01:00
Kenny Levinsen
32d06482d3 seatd-launch: Do not unlink socket path
seatd cleans up after itself and takes care of stale sockets when
applicable, so seatd-launch should not replicate this functionality.
2022-02-21 12:02:31 +01:00
Kenny Levinsen
0864f6a3ac seatd: Ensure socket gets unlinked on error 2022-02-21 12:02:31 +01:00
Kenny Levinsen
157ce68565 seatd: Remove SOCK_PATH and improve cleanup
SOCK_PATH is made redundant by the -s command-line argument added in
a98e0c4ce9. Support was originally left
behind for short-term compatibility, but it should be fine to remove.

Previous socket cleanup is changed to run unconditionally. The cleanup
now fails if the existing file is not a socket.
2022-02-21 12:02:31 +01:00
Kenny Levinsen
f128359332 logind: Always send ping if data is queued
sd_bus_call_method may have read and queued our ping response, so we
cannot assume that a previous ping will make the socket readable.

Instead, always send a ping if read or write queues are not empty, even
if a ping has already been sent.
2022-02-15 13:51:49 +01:00
Kenny Levinsen
b47c79d731 libseat: Use SOCK_CLOEXEC and SOCK_NONBLOCK
This both simplifies our code and fixes an exec fd leak when using
builtin or noop backends.
2022-02-09 23:22:29 +01:00
Simon Ser
96a5de8859 readme: add irc:// link
This allows users to just click the link to join the IRC channel.
2021-12-16 10:40:53 +01:00
Simon Ser
936ff9dbea build: use meson.override_dependency
This allows downstream users to write:

    dependency('libseat', fallback: 'seatd')

instead of having to rely on the seatd/meson.build's variable name:

    dependency('libseat', fallback: ['seatd', 'libseat'])
2021-12-16 10:40:32 +01:00
Simon Ser
f381e22955 build: don't use sh for scdoc
Just use the built-in feed/capture Meson options instead.
2021-11-28 15:41:53 +01:00
Simon Ser
d92fa01f88 build: use list for logind dep
This reduces the boilerplate a bit. Use logind.name() instead of
having a separate source of truth. Requires adapting the checks a
bit because the dep name has a "lib" prefix.
2021-11-28 15:40:56 +01:00
Simon Ser
69cf5c36e0 build: don't use cc.get_supported_arguments for defines
If the compiler errors out on some -DXXX flag, then we're in
trouble. Avoid using cc.get_supported_arguments for defines we
require. Only use it for detecting support for warning flags.
2021-10-28 16:31:17 +02:00
Simon Ser
88529f0856 seatd: don't log errno on EVENT_ERROR
errno won't be set when poll returns EVENT_ERROR.
2021-10-24 00:55:32 +02:00
Simon Ser
cb7a94378b seatd: avoid overwriting errno in set_nonblock error handling
If close fails, it'll mess up errno, and log_errorf will print a
non-sensical value.
2021-10-24 00:52:08 +02:00
25 changed files with 406 additions and 226 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 SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/dri/card0
timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./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 SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0
timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./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 SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0
timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0
- smoketest-builtin: |
timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0

24
.builds/netbsd.yml Normal file
View file

@ -0,0 +1,24 @@
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.
Currently supports Linux and FreeBSD, and has experimental NetBSD support.
## 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 to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel).
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).

View file

@ -2,10 +2,6 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#if defined(__linux__)
#include <sys/sysmacros.h>
#endif
#include "drm.h"
// From libdrm
@ -15,6 +11,7 @@
#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);
@ -24,21 +21,20 @@ int drm_drop_master(int fd) {
return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
}
#if defined(__linux__)
#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
int path_is_drm(const char *path) {
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;
if (STR_HAS_PREFIX("/dev/dri/", path))
return 1;
return 0;
}
#elif defined(__FreeBSD__)
int path_is_drm(const char *path) {
static const char prefix[] = "/dev/drm/";
static const int prefixlen = STRLEN(prefix);
return strncmp(prefix, path, prefixlen) == 0;
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;
}
#else
#error Unsupported platform

View file

@ -9,14 +9,13 @@
#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);
@ -26,9 +25,15 @@ int path_is_evdev(const char *path) {
int evdev_revoke(int fd) {
return ioctl(fd, EVIOCREVOKE, NULL);
}
#if defined(__linux__)
int dev_is_evdev(dev_t device) {
return major(device) == INPUT_MAJOR;
#elif defined(__NetBSD__) || defined(__OpenBSD__)
int path_is_evdev(const char *path) {
(void)path;
return 0;
}
int evdev_revoke(int fd) {
(void)fd;
return 0;
}
#else
#error Unsupported platform
#endif

View file

@ -21,6 +21,17 @@
#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
@ -134,16 +145,38 @@ 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));
@ -153,7 +186,7 @@ int terminal_open(int vt) {
}
int terminal_current_vt(int fd) {
#if defined(__linux__)
#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
struct vt_stat st;
int res = ioctl(fd, VT_GETSTATE, &st);
close(fd);
@ -231,11 +264,20 @@ 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) {
@ -258,10 +300,19 @@ 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;
}

27
common/wscons.c Normal file
View file

@ -0,0 +1,27 @@
#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,9 +5,4 @@ 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,9 +4,4 @@
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,6 +13,7 @@ enum seat_device_type {
SEAT_DEVICE_TYPE_NORMAL,
SEAT_DEVICE_TYPE_EVDEV,
SEAT_DEVICE_TYPE_DRM,
SEAT_DEVICE_TYPE_WSCONS,
};
struct seat_device {

6
include/wscons.h Normal file
View file

@ -0,0 +1,6 @@
#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_ELOGIND)
#if defined(HAVE_LIBELOGIND)
#include <elogind/sd-bus.h>
#include <elogind/sd-login.h>
#elif defined(HAVE_SYSTEMD)
#elif defined(HAVE_LIBSYSTEMD)
#include <systemd/sd-bus.h>
#include <systemd/sd-login.h>
#else
@ -28,6 +28,14 @@
#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;
@ -41,7 +49,6 @@ struct backend_logind {
bool active;
bool initial_setup;
bool awaiting_pong;
int has_drm;
};
@ -70,13 +77,12 @@ 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;
struct backend_logind *session = userdata;
(void)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;
}
@ -91,14 +97,15 @@ static int send_ping(struct backend_logind *backend) {
}
static void check_pending_events(struct backend_logind *backend) {
if (sd_bus_get_events(backend->bus) <= 0) {
return;
}
if (backend->awaiting_pong) {
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) {
return;
}
// We have events pending execution, so a dispatch is required.
// The sd_bus instance has queued data, 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.
@ -107,7 +114,6 @@ 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) {
@ -286,6 +292,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) {
total_dispatched += dispatched;
}
}
check_pending_events(backend);
return total_dispatched;
}
@ -388,7 +395,7 @@ static int pause_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_e
return 0;
}
if (dev_is_drm(makedev(major, minor)) && strcmp(type, "gone") != 0) {
if (dev_major_is_drm(major) && strcmp(type, "gone") != 0) {
log_debugf("DRM device paused: %s", type);
assert(session->has_drm > 0);
set_active(session, false);
@ -420,7 +427,7 @@ static int resume_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_
return 0;
}
if (dev_is_drm(makedev(major, minor))) {
if (dev_major_is_drm(major)) {
log_debug("DRM device resumed");
assert(session->has_drm > 0);
set_active(session, true);
@ -742,6 +749,7 @@ 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 "noop";
return "seat0";
}
static int open_device(struct libseat *base, const char *path, int *fd) {
(void)base;
int tmpfd = open(path, O_RDWR | O_CLOEXEC);
int tmpfd = open(path, O_RDWR | O_NOCTTY | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK);
if (tmpfd < 0) {
log_errorf("Failed to open device: %s", strerror(errno));
return -1;
@ -109,12 +109,13 @@ static struct libseat *noop_open_seat(const struct libseat_seat_listener *listen
return NULL;
}
if (socketpair(AF_UNIX, SOCK_STREAM, 0, backend->sockets) != 0) {
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 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,32 +42,16 @@ 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, 0);
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 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;
@ -616,29 +600,10 @@ 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, 0, fds) == -1) {
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) == -1) {
log_errorf("Could not create socket pair: %s", strerror(errno));
return NULL;
}
@ -650,6 +615,7 @@ 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};
@ -664,7 +630,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis
res = 1;
goto server_error;
}
set_deathsig(SIGTERM);
log_info("Started embedded seatd");
while (server.running) {
if (poller_poll(&server.poller) == -1) {
log_errorf("Could not poll server socket: %s", strerror(errno));
@ -676,8 +642,10 @@ 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,12 +10,13 @@ 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*
*-n <fd>*
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,8 +24,9 @@ seatd - A seat management daemon
*-g <group>*
Group to own the seatd socket.
*-s <path>*
Where to create the seatd socket. Defaults to `/run/seatd.sock`.
*-l <loglevel>*
Log-level to use. Must be one of debug, info, error or silent. Defaults
to error.
*-v*
Show the version number and quit.
@ -38,17 +39,12 @@ 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
[[ *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"
*SEATD_VTBOUND*
If set to "0", the seat will not be bound to a VT.
# SEE ALSO

View file

@ -1,9 +1,9 @@
project(
'seatd',
'c',
version: '0.6.3',
version: '0.8.0',
license: 'MIT',
meson_version: '>=0.56.0',
meson_version: '>=0.60.0',
default_options: [
'c_std=c11',
'warning_level=3',
@ -22,9 +22,22 @@ if defaultpath == ''
endif
endif
seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir'))
seatdpath = get_option('prefix') / get_option('bindir') / 'seatd'
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',
@ -39,12 +52,13 @@ 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',
)
@ -59,7 +73,7 @@ endif
# Hacks
source_root = meson.current_source_dir().split('/')
build_root = meson.build_root().split('/')
build_root = meson.global_build_root().split('/')
relative_dir_parts = []
i = 0
in_prefix = true
@ -100,6 +114,7 @@ server_files = [
'common/connection.c',
'common/evdev.c',
'common/drm.c',
'common/wscons.c',
'seatd/poller.c',
'seatd/seat.c',
'seatd/client.c',
@ -114,31 +129,26 @@ if with_seatd or with_builtin
private_files += 'libseat/backend/seatd.c'
endif
libseat_c_args = ['-DLIBSEAT=1']
if with_seatd
add_project_arguments('-DSEATD_ENABLED=1', language: 'c')
libseat_c_args += '-DSEATD_ENABLED=1'
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')
foreach logind_provider : ['elogind', 'systemd']
logind = dependency('lib@0@'.format(logind_provider), required: false)
if logind.found()
break
endif
endforeach
logind = dependency(['libelogind', 'libsystemd'], required: false)
else
logind_provider = get_option('libseat-logind')
logind = dependency('lib@0@'.format(logind_provider))
logind = dependency('lib@0@'.format(get_option('libseat-logind')))
endif
if logind.found()
add_project_arguments('-DLOGIND_ENABLED=1', language: 'c')
add_project_arguments('-DHAVE_@0@=1'.format(logind_provider.to_upper()), language: 'c')
libseat_c_args += '-DLOGIND_ENABLED=1'
libseat_c_args += '-DHAVE_@0@=1'.format(logind.name().to_upper())
private_files += [
'libseat/backend/logind.c',
'common/drm.c',
@ -148,11 +158,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
add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c')
libseat_c_args += '-DBUILTIN_ENABLED=1'
private_files += server_files
endif
@ -161,6 +171,7 @@ private_lib = static_library(
private_files,
dependencies: private_deps,
include_directories: [include_directories('.', 'include')],
c_args: libseat_c_args,
)
symbols_file = 'libseat/libseat.syms'
@ -168,12 +179,13 @@ 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: libseat_soversion,
soversion: '@0@'.format(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')
@ -200,20 +212,22 @@ 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
@ -247,7 +261,6 @@ 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']
@ -259,9 +272,9 @@ if scdoc.found()
output,
input: 'man/' + src,
output: output,
command: [
'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.full_path(), output)
],
command: scdoc.get_variable(pkgconfig: 'scdoc'),
feed: true,
capture: true,
install: true,
install_dir: '@0@/man@1@'.format(mandir, section)
)
@ -271,7 +284,7 @@ endif
summary({
'libseat-seatd': with_seatd,
'libseat-builtin': with_builtin,
'libseat-systemd': logind.found() and logind_provider == 'systemd',
'libseat-elogind': logind.found() and logind_provider == 'elogind',
'libseat-systemd': logind.found() and logind.name() == 'libsystemd',
'libseat-elogind': logind.found() and logind.name() == 'libelogind',
'server': with_server,
}, bool_yn: true)

View file

@ -11,21 +11,20 @@
#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 *sockpath = NULL;
while ((c = getopt(argc, argv, "vhs:")) != -1) {
char loglevel[16] = "info";
while ((c = getopt(argc, argv, "vhl:")) != -1) {
switch (c) {
case 's':
sockpath = optarg;
case 'l':
strncpy(loglevel, optarg, sizeof loglevel);
loglevel[sizeof loglevel - 1] = '\0';
break;
case 'v':
printf("seatd-launch version %s\n", SEATD_VERSION);
@ -34,7 +33,7 @@ int main(int argc, char *argv[]) {
printf("%s", usage);
return 0;
case '?':
fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]);
fprintf(stderr, "Try 'seatd-launch -h' for more information.\n");
return 1;
default:
abort();
@ -47,44 +46,30 @@ int main(int argc, char *argv[]) {
}
char **command = &argv[optind];
char sockbuf[256];
if (sockpath == NULL) {
sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid());
sockpath = sockbuf;
}
unlink(sockpath);
int fds[2];
if (pipe(fds) == -1) {
int readiness_pipe[2];
if (pipe(readiness_pipe) == -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(fds[0]);
close(readiness_pipe[0]);
char pipebuf[16] = {0};
snprintf(pipebuf, sizeof pipebuf, "%d", fds[1]);
snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]);
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};
char *env[1] = {NULL};
char *command[] = {"seatd", "-n", pipebuf, "-l", loglevel, "-z", NULL};
execve(SEATD_INSTALLPATH, command, env);
perror("Could not start seatd");
_exit(1);
}
close(fds[1]);
close(readiness_pipe[1]);
// Wait for seatd to be ready
char buf[1] = {0};
@ -99,7 +84,7 @@ int main(int argc, char *argv[]) {
}
struct pollfd fd = {
.fd = fds[0],
.fd = readiness_pipe[0],
.events = POLLIN,
};
@ -114,7 +99,7 @@ int main(int argc, char *argv[]) {
}
if (fd.revents & POLLIN) {
ssize_t n = read(fds[0], buf, 1);
ssize_t n = read(readiness_pipe[0], buf, 1);
if (n == -1 && errno != EINTR) {
perror("Could not read from pipe");
goto error_seatd;
@ -123,17 +108,17 @@ int main(int argc, char *argv[]) {
}
}
}
close(fds[0]);
close(readiness_pipe[0]);
uid_t uid = getuid();
gid_t gid = getgid();
// Restrict access to the socket to just us
if (chown(sockpath, uid, gid) == -1) {
if (chown(SEATD_DEFAULTPATH, uid, gid) == -1) {
perror("Could not chown seatd socket");
goto error_seatd;
}
if (chmod(sockpath, 0700) == -1) {
if (chmod(SEATD_DEFAULTPATH, 0700) == -1) {
perror("Could not chmod socket");
goto error_seatd;
}
@ -153,7 +138,7 @@ int main(int argc, char *argv[]) {
perror("Could not fork target process");
goto error_seatd;
} else if (child == 0) {
setenv("SEATD_SOCK", sockpath, 1);
setenv("SEATD_SOCK", SEATD_DEFAULTPATH, 1);
execvp(command[0], command);
perror("Could not start target");
_exit(1);
@ -170,9 +155,6 @@ 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");
}
@ -186,7 +168,6 @@ int main(int argc, char *argv[]) {
}
error_seatd:
unlink(sockpath);
kill(seatd_child, SIGTERM);
error:
return 1;

View file

@ -14,6 +14,10 @@
#include <sys/un.h>
#endif
#if defined(__NetBSD__)
#include <sys/un.h>
#endif
#include "client.h"
#include "linked_list.h"
#include "log.h"
@ -34,6 +38,40 @@ 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;
@ -49,7 +87,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
return -1;
#error Unsupported platform
#endif
}
@ -81,6 +119,13 @@ 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);
@ -282,7 +327,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;
}
@ -325,6 +370,7 @@ 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) {
@ -461,7 +507,13 @@ 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,6 +17,7 @@
#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);
@ -86,8 +87,8 @@ static int vt_close(int vt) {
return -1;
}
terminal_set_process_switching(ttyfd, true);
terminal_set_keyboard(ttyfd, true);
terminal_set_graphics(ttyfd, false);
terminal_set_keyboard(ttyfd, true);
close(ttyfd);
return 0;
}
@ -106,6 +107,7 @@ 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;
@ -235,6 +237,8 @@ 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;
@ -281,6 +285,9 @@ 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();
@ -333,6 +340,9 @@ 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();
@ -382,6 +392,9 @@ 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();
@ -525,7 +538,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,35 +57,23 @@ 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"
" -s <path> Where to create the seatd socket\n"
" -l <loglevel> Log-level, one of debug, info, error or silent\n"
" -v Show the version number\n"
"\n";
int c;
int uid = -1, gid = -1;
int readiness = -1;
const char *socket_path = getenv("SEATD_SOCK");
while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -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) {
switch (c) {
case 'n':
readiness = atoi(optarg);
@ -94,10 +82,11 @@ 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);
@ -108,6 +97,10 @@ 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);
@ -117,6 +110,31 @@ 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;
@ -131,33 +149,46 @@ int main(int argc, char *argv[]) {
}
}
if (socket_path == NULL) {
socket_path = SEATD_DEFAULTPATH;
log_init();
libseat_set_log_level(level);
struct stat st;
if (stat(socket_path, &st) == 0) {
log_info("Removing leftover seatd socket");
unlink(socket_path);
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;
}
}
}
struct server server = {0};
if (server_init(&server) == -1) {
log_errorf("server_create failed: %s", strerror(errno));
log_errorf("server_init failed: %s", strerror(errno));
return 1;
}
int socket_fd = open_socket(socket_path, uid, gid);
int ret = 1;
int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid);
if (socket_fd == -1) {
log_error("Could not create server socket");
server_finish(&server);
return 1;
goto error_server;
}
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);
server_finish(&server);
return 1;
goto error_socket;
}
log_info("seatd started");
@ -172,12 +203,18 @@ int main(int argc, char *argv[]) {
while (server.running) {
if (poller_poll(&server.poller) == -1) {
log_errorf("Poller failed: %s", strerror(errno));
return 1;
goto error_socket;
}
}
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 0;
return ret;
}

View file

@ -123,12 +123,18 @@ static int set_nonblock(int fd) {
int server_add_client(struct server *server, int fd) {
if (set_nonblock(fd) != 0) {
close(fd);
log_errorf("Could not prepare new client socket: %s", strerror(errno));
close(fd);
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) {
@ -146,7 +152,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_errorf("Server socket received an error: %s", strerror(errno));
log_error("Server socket received an error");
return -1;
}

View file

@ -123,6 +123,10 @@ 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);