Compare commits
67 commits
Author | SHA1 | Date | |
---|---|---|---|
b4462cb033 | |||
cc09e26976 | |||
![]() |
0746edbeae | ||
![]() |
3e9ef69f14 | ||
a8aee6fa70 | |||
4b2ecdf936 | |||
f2ff233c26 | |||
dbaa859f28 | |||
![]() |
1bd042e5b0 | ||
![]() |
56720a6275 | ||
![]() |
e5b018def8 | ||
![]() |
3e0d510b2c | ||
![]() |
207e2a5936 | ||
![]() |
9b8b6e0bf8 | ||
![]() |
14355639f8 | ||
![]() |
a803ba0502 | ||
![]() |
6888653a8d | ||
![]() |
2842f0e2b1 | ||
![]() |
85d0bf5943 | ||
![]() |
8f8c9558e6 | ||
![]() |
0462e9331d | ||
![]() |
684dd61945 | ||
![]() |
d5539dead8 | ||
![]() |
845256009b | ||
![]() |
a5f9a2a2c8 | ||
![]() |
4ad48cb305 | ||
![]() |
1990f9b034 | ||
![]() |
bb0efb65b3 | ||
![]() |
ce6a6b7d2e | ||
![]() |
8dc6a50d88 | ||
![]() |
795cf169e7 | ||
![]() |
46c83972fe | ||
![]() |
abcecbb53b | ||
![]() |
ae42d05513 | ||
![]() |
0d6bdf4f01 | ||
![]() |
466efea49b | ||
![]() |
9bbdf0f0b8 | ||
![]() |
3eb0db57bb | ||
![]() |
ed90ed62cd | ||
![]() |
a44476ce65 | ||
![]() |
10658dc543 | ||
![]() |
32d06482d3 | ||
![]() |
0864f6a3ac | ||
![]() |
157ce68565 | ||
![]() |
f128359332 | ||
![]() |
b47c79d731 | ||
![]() |
96a5de8859 | ||
![]() |
936ff9dbea | ||
![]() |
f381e22955 | ||
![]() |
d92fa01f88 | ||
![]() |
69cf5c36e0 | ||
![]() |
88529f0856 | ||
![]() |
cb7a94378b | ||
![]() |
88db55f606 | ||
![]() |
e35c9cd02e | ||
![]() |
ec0d6565bb | ||
![]() |
8e5c00e7c8 | ||
![]() |
d2193b45ff | ||
![]() |
262ccef84e | ||
![]() |
1c376ca9b1 | ||
![]() |
e2baadc230 | ||
![]() |
db08fb921f | ||
![]() |
2eee9aa445 | ||
![]() |
0f20175752 | ||
![]() |
ebf512c2bf | ||
![]() |
907b75de1a | ||
![]() |
4091ba2c07 |
30 changed files with 592 additions and 313 deletions
|
@ -13,15 +13,16 @@ tasks:
|
|||
meson -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dlibseat-logind=disabled -Dexamples=enabled build seatd
|
||||
- build: |
|
||||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
- unittest: |
|
||||
ninja -C build test
|
||||
- scan-build: |
|
||||
ninja -C build scan-build
|
||||
[ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ]
|
||||
- smoketest: |
|
||||
timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh
|
||||
timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/dri/card0
|
||||
- smoketest-builtin: |
|
||||
timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh
|
||||
timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/dri/card0
|
||||
- check-format: |
|
||||
ninja -C build clang-format
|
||||
git -C seatd diff --exit-code
|
||||
|
|
|
@ -12,12 +12,19 @@ tasks:
|
|||
meson -Db_sanitize=address -Dlibseat-logind=auto -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled build seatd
|
||||
- build: |
|
||||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
- unittest: |
|
||||
ninja -C build test
|
||||
- scan-build: |
|
||||
ninja -C build scan-build
|
||||
[ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ]
|
||||
- smoketest: |
|
||||
timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh
|
||||
timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0
|
||||
- smoketest-builtin: |
|
||||
timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh
|
||||
timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0
|
||||
- smoketest-logind: |
|
||||
# Turn off systemd-logind and patch our session to be tied to seat0 on VT 6
|
||||
sudo systemctl stop systemd-logind
|
||||
echo -e "ACTIVE=$XDG_SESSION_ID\nACTIVE_UID=$UID\nSESSIONS=$XDG_SESSION_ID\nUIDS=$UID\n" | sudo tee -a /run/systemd/seats/seat0 > /dev/null
|
||||
echo -e "SEAT=seat0\nVTNR=6\n" | sudo tee -a /run/systemd/sessions/$XDG_SESSION_ID > /dev/null
|
||||
timeout -s KILL 30s sudo LIBSEAT_BACKEND=logind ./build/simpletest /dev/input/event0
|
||||
|
|
|
@ -14,6 +14,7 @@ tasks:
|
|||
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
|
||||
timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh
|
||||
sudo ninja -C build install
|
||||
timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0
|
||||
- smoketest-builtin: |
|
||||
timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh
|
||||
timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0
|
||||
|
|
24
.builds/netbsd.yml
Normal file
24
.builds/netbsd.yml
Normal 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
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Devices that exist on sr.ht
|
||||
if [ -e "/dev/input/event0" ]
|
||||
then
|
||||
file="/dev/input/event0"
|
||||
elif [ -e "/dev/dri/card0" ]
|
||||
then
|
||||
file="/dev/dri/card0"
|
||||
else
|
||||
echo "No useful device file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Run simpletest a few times
|
||||
#
|
||||
cnt=0
|
||||
while [ "$cnt" -lt 2 ]
|
||||
do
|
||||
echo "Simpletest run $((cnt+1))"
|
||||
if ! sudo LIBSEAT_BACKEND=builtin ./build/simpletest $file
|
||||
then
|
||||
echo "Simpletest failed"
|
||||
exit $res
|
||||
fi
|
||||
cnt=$((cnt+1))
|
||||
done
|
||||
|
||||
echo "smoketest-builtin completed"
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Devices that exist on sr.ht
|
||||
if [ -e "/dev/input/event0" ]
|
||||
then
|
||||
file="/dev/input/event0"
|
||||
elif [ -e "/dev/dri/card0" ]
|
||||
then
|
||||
file="/dev/dri/card0"
|
||||
else
|
||||
echo "No useful device file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export SEATD_LOGLEVEL=debug
|
||||
export PATH=$(pwd)/build:$PATH
|
||||
#
|
||||
# Run simpletest a few times
|
||||
#
|
||||
cnt=0
|
||||
while [ "$cnt" -lt 2 ]
|
||||
do
|
||||
echo "Simpletest run $((cnt+1))"
|
||||
if ! sudo -E seatd-launch ./build/simpletest $file
|
||||
then
|
||||
echo "Simpletest failed"
|
||||
exit 1
|
||||
fi
|
||||
cnt=$((cnt+1))
|
||||
done
|
||||
|
||||
echo "smoketest-seatd completed"
|
|
@ -2,7 +2,7 @@
|
|||
IndentWidth: 8
|
||||
TabWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
UseTab: Always
|
||||
UseTab: ForContinuationAndIndentation
|
||||
ColumnLimit: 100
|
||||
|
||||
AlignConsecutiveMacros: true
|
||||
|
|
|
@ -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).
|
||||
|
|
32
common/drm.c
32
common/drm.c
|
@ -2,19 +2,16 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "drm.h"
|
||||
|
||||
// From libdrm
|
||||
#define DRM_IOCTL_BASE 'd'
|
||||
#define DRM_IO(nr) _IO(DRM_IOCTL_BASE, nr)
|
||||
#define DRM_IOCTL_BASE 'd'
|
||||
#define DRM_IO(nr) _IO(DRM_IOCTL_BASE, nr)
|
||||
#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 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,14 +13,25 @@
|
|||
#include <linux/vt.h>
|
||||
#define K_ENABLE K_UNICODE
|
||||
#define K_DISABLE K_OFF
|
||||
#define FRSIG 0
|
||||
#define FRSIG 0
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/consio.h>
|
||||
#include <sys/kbio.h>
|
||||
#include <termios.h>
|
||||
#define K_ENABLE K_XLATE
|
||||
#define K_DISABLE K_RAW
|
||||
#define FRSIG SIGIO
|
||||
#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
27
common/wscons.c
Normal 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
|
|
@ -43,7 +43,11 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
while (active == 0) {
|
||||
fprintf(stderr, "waiting for activation...\n");
|
||||
libseat_dispatch(backend, -1);
|
||||
if (libseat_dispatch(backend, -1) == -1) {
|
||||
libseat_close_seat(backend);
|
||||
fprintf(stderr, "libseat_dispatch() failed: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "active!\n");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef _SEATD_CONSTANTS_H
|
||||
#define _SEATD_CONSTANTS_H
|
||||
|
||||
#define MAX_PATH_LEN 256
|
||||
#define MAX_SEAT_LEN 64
|
||||
#define MAX_PATH_LEN 256
|
||||
#define MAX_SEAT_LEN 64
|
||||
#define MAX_SEAT_DEVICES 128
|
||||
#define MAX_SESSION_LEN 64
|
||||
#define MAX_SESSION_LEN 64
|
||||
|
||||
#define CLIENT_EVENT(opcode) (opcode)
|
||||
#define SERVER_EVENT(opcode) ((opcode) + (1 << 15))
|
||||
|
@ -15,6 +15,7 @@
|
|||
#define CLIENT_CLOSE_DEVICE CLIENT_EVENT(4)
|
||||
#define CLIENT_DISABLE_SEAT CLIENT_EVENT(5)
|
||||
#define CLIENT_SWITCH_SESSION CLIENT_EVENT(6)
|
||||
#define CLIENT_PING CLIENT_EVENT(7)
|
||||
|
||||
#define SERVER_SEAT_OPENED SERVER_EVENT(1)
|
||||
#define SERVER_SEAT_CLOSED SERVER_EVENT(2)
|
||||
|
@ -22,7 +23,8 @@
|
|||
#define SERVER_DEVICE_CLOSED SERVER_EVENT(4)
|
||||
#define SERVER_DISABLE_SEAT SERVER_EVENT(5)
|
||||
#define SERVER_ENABLE_SEAT SERVER_EVENT(6)
|
||||
#define SERVER_ERROR SERVER_EVENT(0x7FFF)
|
||||
#define SERVER_PONG SERVER_EVENT(7)
|
||||
#define SERVER_ERROR SERVER_EVENT(0x7FFF)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
|
@ -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
6
include/wscons.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _SEATD_WSCONS_H
|
||||
#define _SEATD_WSCONS_H
|
||||
|
||||
int path_is_wscons(const char *path);
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
|
@ -67,6 +75,47 @@ static int close_seat(struct libseat *base) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||
(void)ret_error;
|
||||
(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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_ping(struct backend_logind *backend) {
|
||||
int ret = sd_bus_call_method_async(backend->bus, NULL, "org.freedesktop.login1",
|
||||
"/org/freedesktop/login1", "org.freedesktop.DBus.Peer",
|
||||
"Ping", ping_handler, backend, "");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
int ret = send_ping(backend);
|
||||
if (ret < 0) {
|
||||
log_errorf("Could not send ping message: %s", strerror(-ret));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int open_device(struct libseat *base, const char *path, int *fd) {
|
||||
struct backend_logind *session = backend_logind_from_libseat_backend(base);
|
||||
|
||||
|
@ -113,9 +162,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) {
|
|||
}
|
||||
|
||||
*fd = tmpfd;
|
||||
|
||||
out:
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
check_pending_events(session);
|
||||
return tmpfd;
|
||||
}
|
||||
|
||||
|
@ -150,7 +201,7 @@ static int close_device(struct libseat *base, int device_id) {
|
|||
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
check_pending_events(session);
|
||||
return ret < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
@ -173,6 +224,7 @@ static int switch_session(struct libseat *base, int s) {
|
|||
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
check_pending_events(session);
|
||||
return ret < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
@ -240,6 +292,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) {
|
|||
total_dispatched += dispatched;
|
||||
}
|
||||
}
|
||||
check_pending_events(backend);
|
||||
return total_dispatched;
|
||||
}
|
||||
|
||||
|
@ -253,10 +306,11 @@ static struct backend_logind *backend_logind_from_libseat_backend(struct libseat
|
|||
return (struct backend_logind *)base;
|
||||
}
|
||||
|
||||
static bool session_activate(struct backend_logind *session) {
|
||||
static int session_activate(struct backend_logind *session) {
|
||||
sd_bus_message *msg = NULL;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
// Note: the Activate call might not make the session active immediately
|
||||
int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", session->path,
|
||||
"org.freedesktop.login1.Session", "Activate", &error, &msg, "");
|
||||
if (ret < 0) {
|
||||
|
@ -265,10 +319,26 @@ static bool session_activate(struct backend_logind *session) {
|
|||
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
return ret >= 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool take_control(struct backend_logind *session) {
|
||||
static int session_check_active(struct backend_logind *session) {
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int active = 0;
|
||||
int ret = sd_bus_get_property_trivial(session->bus, "org.freedesktop.login1", session->path,
|
||||
"org.freedesktop.login1.Session", "Active", &error,
|
||||
'b', &active);
|
||||
if (ret < 0) {
|
||||
log_errorf("Could not check if session is active: %s", error.message);
|
||||
} else {
|
||||
session->active = (bool)active;
|
||||
}
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int take_control(struct backend_logind *session) {
|
||||
sd_bus_message *msg = NULL;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
|
@ -281,7 +351,7 @@ static bool take_control(struct backend_logind *session) {
|
|||
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
return ret >= 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_control(struct backend_logind *session) {
|
||||
|
@ -325,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);
|
||||
|
@ -357,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);
|
||||
|
@ -467,7 +537,7 @@ error:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool add_signal_matches(struct backend_logind *backend) {
|
||||
static int add_signal_matches(struct backend_logind *backend) {
|
||||
static const char *logind = "org.freedesktop.login1";
|
||||
static const char *session_interface = "org.freedesktop.login1.Session";
|
||||
static const char *property_interface = "org.freedesktop.DBus.Properties";
|
||||
|
@ -477,34 +547,34 @@ static bool add_signal_matches(struct backend_logind *backend) {
|
|||
"PauseDevice", pause_device, backend);
|
||||
if (ret < 0) {
|
||||
log_errorf("Could not add D-Bus match: %s", strerror(-ret));
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sd_bus_match_signal(backend->bus, NULL, logind, backend->path, session_interface,
|
||||
"ResumeDevice", resume_device, backend);
|
||||
if (ret < 0) {
|
||||
log_errorf("Could not add D-Bus match: %s", strerror(-ret));
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sd_bus_match_signal(backend->bus, NULL, logind, backend->path, property_interface,
|
||||
"PropertiesChanged", properties_changed, backend);
|
||||
if (ret < 0) {
|
||||
log_errorf("Could not add D-Bus match: %s", strerror(-ret));
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sd_bus_match_signal(backend->bus, NULL, logind, backend->seat_path, property_interface,
|
||||
"PropertiesChanged", properties_changed, backend);
|
||||
if (ret < 0) {
|
||||
log_errorf("Could not add D-Bus match: %s", strerror(-ret));
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool find_session_path(struct backend_logind *session) {
|
||||
static int find_session_path(struct backend_logind *session) {
|
||||
int ret;
|
||||
sd_bus_message *msg = NULL;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
@ -529,10 +599,10 @@ out:
|
|||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
return ret >= 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool find_seat_path(struct backend_logind *session) {
|
||||
static int find_seat_path(struct backend_logind *session) {
|
||||
int ret;
|
||||
sd_bus_message *msg = NULL;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
@ -557,10 +627,10 @@ out:
|
|||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
return ret >= 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool get_display_session(char **session_id) {
|
||||
static int get_display_session(char **session_id) {
|
||||
assert(session_id != NULL);
|
||||
char *xdg_session_id = getenv("XDG_SESSION_ID");
|
||||
int ret;
|
||||
|
@ -593,12 +663,12 @@ static bool get_display_session(char **session_id) {
|
|||
|
||||
success:
|
||||
assert(*session_id != NULL);
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(*session_id);
|
||||
*session_id = NULL;
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_type(struct backend_logind *backend, const char *type) {
|
||||
|
@ -623,11 +693,13 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!get_display_session(&backend->id)) {
|
||||
int ret;
|
||||
ret = get_display_session(&backend->id);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
int ret = sd_session_get_seat(backend->id, &backend->seat);
|
||||
ret = sd_session_get_seat(backend->id, &backend->seat);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -637,23 +709,33 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (!find_session_path(backend)) {
|
||||
ret = find_session_path(backend);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!find_seat_path(backend)) {
|
||||
ret = find_seat_path(backend);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!add_signal_matches(backend)) {
|
||||
ret = add_signal_matches(backend);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!session_activate(backend)) {
|
||||
ret = session_activate(backend);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!take_control(backend)) {
|
||||
ret = session_check_active(backend);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = take_control(backend);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -663,15 +745,16 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list
|
|||
}
|
||||
|
||||
backend->initial_setup = true;
|
||||
backend->active = true;
|
||||
backend->seat_listener = listener;
|
||||
backend->seat_listener_data = data;
|
||||
backend->base.impl = &logind_impl;
|
||||
|
||||
check_pending_events(backend);
|
||||
return &backend->base;
|
||||
|
||||
error:
|
||||
destroy(backend);
|
||||
errno = -ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -36,37 +36,22 @@ struct backend_seatd {
|
|||
const struct libseat_seat_listener *seat_listener;
|
||||
void *seat_listener_data;
|
||||
struct linked_list pending_events;
|
||||
bool awaiting_pong;
|
||||
bool error;
|
||||
|
||||
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;
|
||||
|
@ -243,6 +228,12 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) {
|
|||
while (connection_get(&backend->connection, &header, sizeof header) != -1) {
|
||||
packets++;
|
||||
switch (header.opcode) {
|
||||
case SERVER_PONG:
|
||||
// We care about whether or not the answer has been
|
||||
// read from the connection, so handle it here instead
|
||||
// of pushing it to the pending event list.
|
||||
backend->awaiting_pong = false;
|
||||
break;
|
||||
case SERVER_DISABLE_SEAT:
|
||||
case SERVER_ENABLE_SEAT:
|
||||
if (queue_event(backend, header.opcode) == -1) {
|
||||
|
@ -450,6 +441,36 @@ static const char *seat_name(struct libseat *base) {
|
|||
return backend->seat_name;
|
||||
}
|
||||
|
||||
static int send_ping(struct backend_seatd *backend) {
|
||||
struct proto_header header = {
|
||||
.opcode = CLIENT_PING,
|
||||
.size = 0,
|
||||
};
|
||||
if (conn_put(backend, &header, sizeof header) == -1 || conn_flush(backend) == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_pending_events(struct backend_seatd *backend) {
|
||||
if (linked_list_empty(&backend->pending_events)) {
|
||||
return;
|
||||
}
|
||||
if (backend->awaiting_pong) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 seatd, so that the
|
||||
// user will be woken up by its response.
|
||||
if (send_ping(backend) == -1) {
|
||||
log_errorf("Could not send ping request: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
backend->awaiting_pong = true;
|
||||
}
|
||||
|
||||
static int open_device(struct libseat *base, const char *path, int *fd) {
|
||||
struct backend_seatd *backend = backend_seatd_from_libseat_backend(base);
|
||||
if (backend->error) {
|
||||
|
@ -481,11 +502,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) {
|
|||
goto error;
|
||||
}
|
||||
|
||||
execute_events(backend);
|
||||
check_pending_events(backend);
|
||||
return rmsg.device_id;
|
||||
|
||||
error:
|
||||
execute_events(backend);
|
||||
check_pending_events(backend);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -516,11 +537,11 @@ static int close_device(struct libseat *base, int device_id) {
|
|||
goto error;
|
||||
}
|
||||
|
||||
execute_events(backend);
|
||||
check_pending_events(backend);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
execute_events(backend);
|
||||
check_pending_events(backend);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -579,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;
|
||||
}
|
||||
|
@ -613,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};
|
||||
|
@ -627,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));
|
||||
|
@ -639,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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
78
meson.build
78
meson.build
|
@ -1,9 +1,9 @@
|
|||
project(
|
||||
'seatd',
|
||||
'c',
|
||||
version: '0.6.1',
|
||||
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,7 +22,22 @@ if defaultpath == ''
|
|||
endif
|
||||
endif
|
||||
|
||||
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',
|
||||
|
@ -37,11 +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)
|
||||
]),
|
||||
language: 'c',
|
||||
)
|
||||
|
@ -56,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
|
||||
|
@ -97,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',
|
||||
|
@ -111,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',
|
||||
|
@ -145,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
|
||||
|
||||
|
@ -158,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'
|
||||
|
@ -165,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')
|
||||
|
@ -197,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
|
||||
|
||||
|
@ -244,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']
|
||||
|
@ -256,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)
|
||||
)
|
||||
|
@ -268,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)
|
||||
|
|
|
@ -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,35 +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[8];
|
||||
sprintf(pipebuf, "%d", fds[1]);
|
||||
char pipebuf[16] = {0};
|
||||
snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]);
|
||||
|
||||
execlp("seatd", "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};
|
||||
|
@ -90,7 +84,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
struct pollfd fd = {
|
||||
.fd = fds[0],
|
||||
.fd = readiness_pipe[0],
|
||||
.events = POLLIN,
|
||||
};
|
||||
|
||||
|
@ -105,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;
|
||||
|
@ -114,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;
|
||||
}
|
||||
|
@ -144,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);
|
||||
|
@ -161,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");
|
||||
}
|
||||
|
@ -177,7 +168,6 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
error_seatd:
|
||||
unlink(sockpath);
|
||||
kill(seatd_child, SIGTERM);
|
||||
error:
|
||||
return 1;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -309,8 +354,23 @@ error:
|
|||
return client_send_error(client, errno);
|
||||
}
|
||||
|
||||
static int handle_ping(struct client *client) {
|
||||
struct proto_header header = {
|
||||
.opcode = SERVER_PONG,
|
||||
.size = 0,
|
||||
};
|
||||
|
||||
if (connection_put(&client->connection, &header, sizeof header) == -1) {
|
||||
log_errorf("Could not write response: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -372,6 +432,14 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s
|
|||
res = handle_disable_seat(client);
|
||||
break;
|
||||
}
|
||||
case CLIENT_PING: {
|
||||
if (size != 0) {
|
||||
log_error("Protocol error: invalid ping message");
|
||||
return -1;
|
||||
}
|
||||
res = handle_ping(client);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log_errorf("Protocol error: unknown opcode: %d", opcode);
|
||||
res = -1;
|
||||
|
@ -439,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;
|
||||
}
|
||||
|
||||
|
|
17
seatd/seat.c
17
seatd/seat.c
|
@ -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
|
||||
|
|
117
seatd/seatd.c
117
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,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"
|
||||
" -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;
|
||||
struct stat st;
|
||||
if (stat(socket_path, &st) == 0) {
|
||||
log_info("Removing leftover seatd socket");
|
||||
unlink(socket_path);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue