From 69d57aaf332268e3dea8795c2b9f091059f3b5b4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 20:27:02 +0200 Subject: [PATCH 001/211] libseat: Assert that listener is non-NULL --- libseat/backend/seatd.c | 25 +++++++++---------------- libseat/libseat.c | 2 +- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 413282e..6321d39 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -88,20 +88,6 @@ static struct backend_seatd *backend_seatd_from_libseat_backend(struct libseat * return (struct backend_seatd *)base; } -static void handle_enable_seat(struct backend_seatd *backend) { - log_info("Enabling seat"); - if (backend->seat_listener != NULL && backend->seat_listener->enable_seat != NULL) { - backend->seat_listener->enable_seat(&backend->base, backend->seat_listener_data); - } -} - -static void handle_disable_seat(struct backend_seatd *backend) { - log_info("Disabling seat"); - if (backend->seat_listener != NULL && backend->seat_listener->disable_seat != NULL) { - backend->seat_listener->disable_seat(&backend->base, backend->seat_listener_data); - } -} - static size_t read_header(struct connection *connection, uint16_t expected_opcode) { struct proto_header header; if (connection_get(connection, &header, sizeof header) == -1) { @@ -155,12 +141,17 @@ static void execute_events(struct backend_seatd *backend) { switch (opcode) { case SERVER_DISABLE_SEAT: - handle_disable_seat(backend); + log_info("Disabling seat"); + backend->seat_listener->disable_seat(&backend->base, + backend->seat_listener_data); break; case SERVER_ENABLE_SEAT: - handle_enable_seat(backend); + log_info("Enabling seat"); + backend->seat_listener->enable_seat(&backend->base, + backend->seat_listener_data); break; default: + log_errorf("Invalid opcode: %d", opcode); abort(); } } @@ -283,6 +274,8 @@ static void destroy(struct backend_seatd *backend) { } static struct libseat *_open_seat(struct libseat_seat_listener *listener, void *data, int fd) { + assert(listener != NULL); + assert(listener->enable_seat != NULL && listener->disable_seat != NULL); struct backend_seatd *backend = calloc(1, sizeof(struct backend_seatd)); if (backend == NULL) { close(fd); diff --git a/libseat/libseat.c b/libseat/libseat.c index d7ab361..11d3786 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -32,7 +32,7 @@ static const struct named_backend impls[] = { #endif struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void *data) { - if (listener == NULL) { + if (listener == NULL || listener->enable_seat == NULL || listener->disable_seat == NULL) { errno = EINVAL; return NULL; } From 8b4d139873acfb3351ad335830b2689720d21552 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 20:31:51 +0200 Subject: [PATCH 002/211] libseat: Improve logging with seatd conn helpers Add helpers around connection access to have all logging centralized and reduce code duplication. Improve existing helpers to further reduce code duplication. The seatd backend should have much better logging after this. --- common/connection.c | 11 ++- include/connection.h | 2 +- libseat/backend/seatd.c | 195 ++++++++++++++++++++-------------------- 3 files changed, 102 insertions(+), 106 deletions(-) diff --git a/common/connection.c b/common/connection.c index a6739c0..6b2c366 100644 --- a/common/connection.c +++ b/common/connection.c @@ -284,15 +284,14 @@ int connection_get(struct connection *connection, void *dst, size_t count) { return count; } -int connection_get_fd(struct connection *connection) { - int fd; - if (sizeof fd > connection_buffer_size(&connection->fds_in)) { +int connection_get_fd(struct connection *connection, int *fd) { + if (sizeof(int) > connection_buffer_size(&connection->fds_in)) { errno = EAGAIN; return -1; } - connection_buffer_copy(&connection->fds_in, &fd, sizeof fd); - connection_buffer_consume(&connection->fds_in, sizeof fd); - return fd; + connection_buffer_copy(&connection->fds_in, fd, sizeof(int)); + connection_buffer_consume(&connection->fds_in, sizeof(int)); + return 0; } void connection_close_fds(struct connection *connection) { diff --git a/include/connection.h b/include/connection.h index 3e15403..d32e766 100644 --- a/include/connection.h +++ b/include/connection.h @@ -28,7 +28,7 @@ int connection_put_fd(struct connection *connection, int fd); size_t connection_pending(struct connection *connection); int connection_get(struct connection *connection, void *dst, size_t count); -int connection_get_fd(struct connection *connection); +int connection_get_fd(struct connection *connection, int *fd); void connection_restore(struct connection *connection, size_t count); void connection_close_fds(struct connection *connection); diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 6321d39..718838a 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -58,9 +58,11 @@ static int seatd_connect(void) { } addr = {{0}}; int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { + log_errorf("Could not create socket: %s", strerror(errno)); return -1; } if (set_nonblock(fd) == -1) { + log_errorf("Could not make socket non-blocking: %s", strerror(errno)); close(fd); return -1; } @@ -72,6 +74,7 @@ static int seatd_connect(void) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (connect(fd, &addr.generic, size) == -1) { + log_debugf("Could not connect to socket: %s", strerror(errno)); close(fd); return -1; }; @@ -88,21 +91,54 @@ static struct backend_seatd *backend_seatd_from_libseat_backend(struct libseat * return (struct backend_seatd *)base; } -static size_t read_header(struct connection *connection, uint16_t expected_opcode) { +static inline int conn_put(struct backend_seatd *backend, const void *data, const size_t data_len) { + if (connection_put(&backend->connection, data, data_len) == -1) { + log_errorf("Could not send request: %s", strerror(errno)); + return -1; + } + return 0; +} + +static inline int conn_flush(struct backend_seatd *backend) { + if (connection_flush(&backend->connection) == -1) { + log_errorf("Could not flush connection: %s", strerror(errno)); + return -1; + } + return 0; +} + +static inline int conn_get(struct backend_seatd *backend, void *target, const size_t target_len) { + if (connection_get(&backend->connection, target, target_len) == -1) { + log_error("Invalid message: insufficient data received"); + errno = EBADMSG; + return -1; + } + return 0; +} + +static inline int conn_get_fd(struct backend_seatd *backend, int *fd) { + if (connection_get_fd(&backend->connection, fd) == -1) { + log_error("Invalid message: insufficient data received"); + errno = EBADMSG; + return -1; + } + return 0; +} + +static size_t read_header(struct backend_seatd *backend, uint16_t expected_opcode, + size_t expected_size, bool variable) { struct proto_header header; - if (connection_get(connection, &header, sizeof header) == -1) { - log_error("Received invalid message: header too short"); + if (conn_get(backend, &header, sizeof header) == -1) { return SIZE_MAX; } if (header.opcode != expected_opcode) { - connection_restore(connection, sizeof header); + connection_restore(&backend->connection, sizeof header); struct proto_server_error msg; if (header.opcode != SERVER_ERROR) { - log_errorf("Received invalid message: expected opcode %d, received opcode %d", + log_errorf("Unexpected response: expected opcode %d, received opcode %d", expected_opcode, header.opcode); errno = EBADMSG; - } else if (connection_get(connection, &msg, sizeof msg) == -1) { - log_error("Received invalid message"); + } else if (conn_get(backend, &msg, sizeof msg) == -1) { errno = EBADMSG; } else { errno = msg.error_code; @@ -110,12 +146,19 @@ static size_t read_header(struct connection *connection, uint16_t expected_opcod return SIZE_MAX; } + if ((!variable && header.size != expected_size) || (variable && header.size < expected_size)) { + log_errorf("Invalid message: does not match expected size: variable: %d, header.size: %d, expected size: %zd", + variable, header.size, expected_size); + errno = EBADMSG; + return SIZE_MAX; + } return header.size; } static int queue_event(struct backend_seatd *backend, int opcode) { struct pending_event *ev = calloc(1, sizeof(struct pending_event)); if (ev == NULL) { + log_errorf("Allocation failed: %s", strerror(errno)); return -1; } @@ -211,8 +254,7 @@ static int poll_connection(struct backend_seatd *backend, int timeout) { } static int dispatch(struct backend_seatd *backend) { - if (connection_flush(&backend->connection) == -1) { - log_errorf("Could not flush connection: %s", strerror(errno)); + if (conn_flush(backend) == -1) { return -1; } int opcode = 0, res = 0; @@ -278,9 +320,10 @@ static struct libseat *_open_seat(struct libseat_seat_listener *listener, void * assert(listener->enable_seat != NULL && listener->disable_seat != NULL); struct backend_seatd *backend = calloc(1, sizeof(struct backend_seatd)); if (backend == NULL) { - close(fd); - return NULL; + log_errorf("Allocation failed: %s", strerror(errno)); + goto alloc_error; } + backend->seat_listener = listener; backend->seat_listener_data = data; backend->connection.fd = fd; @@ -291,42 +334,31 @@ static struct libseat *_open_seat(struct libseat_seat_listener *listener, void * .opcode = CLIENT_OPEN_SEAT, .size = 0, }; - - if (connection_put(&backend->connection, &header, sizeof header) == -1 || - dispatch(backend) == -1) { - destroy(backend); - return NULL; - } - - size_t size = read_header(&backend->connection, SERVER_SEAT_OPENED); - if (size == SIZE_MAX) { - destroy(backend); - return NULL; + if (conn_put(backend, &header, sizeof header) == -1 || dispatch(backend) == -1) { + goto backend_error; } struct proto_server_seat_opened rmsg; - if (sizeof rmsg > size) { - goto badmsg_error; + size_t size = read_header(backend, SERVER_SEAT_OPENED, sizeof rmsg, true); + if (size == SIZE_MAX || conn_get(backend, &rmsg, sizeof rmsg) == -1) { + goto backend_error; } - - if (connection_get(&backend->connection, &rmsg, sizeof rmsg) == -1) { - goto badmsg_error; - }; - - if (sizeof rmsg + rmsg.seat_name_len > size || - rmsg.seat_name_len >= sizeof backend->seat_name) { - goto badmsg_error; + if (rmsg.seat_name_len != size - sizeof rmsg) { + log_errorf("Invalid message: seat_name_len does not match remaining message size (%d != %zd)", + rmsg.seat_name_len, size); + errno = EBADMSG; + goto backend_error; + } + if (conn_get(backend, backend->seat_name, rmsg.seat_name_len) == -1) { + goto backend_error; } - - if (connection_get(&backend->connection, backend->seat_name, rmsg.seat_name_len) == -1) { - goto badmsg_error; - }; return &backend->base; -badmsg_error: - log_error("Received invalid message"); - errno = EBADMSG; +backend_error: + destroy(backend); +alloc_error: + close(fd); return NULL; } @@ -346,21 +378,20 @@ static int close_seat(struct libseat *base) { .opcode = CLIENT_CLOSE_SEAT, .size = 0, }; - - if (connection_put(&backend->connection, &header, sizeof header) == -1 || - dispatch(backend) == -1) { - destroy(backend); - return -1; + if (conn_put(backend, &header, sizeof header) == -1 || dispatch(backend) == -1) { + goto error; } - size_t size = read_header(&backend->connection, SERVER_SEAT_CLOSED); - if (size == SIZE_MAX) { - destroy(backend); - return -1; + if (read_header(backend, SERVER_SEAT_CLOSED, 0, false) == SIZE_MAX) { + goto error; } destroy(backend); return 0; + +error: + destroy(backend); + return -1; } static const char *seat_name(struct libseat *base) { @@ -384,38 +415,19 @@ static int open_device(struct libseat *base, const char *path, int *fd) { .opcode = CLIENT_OPEN_DEVICE, .size = sizeof msg + pathlen, }; - - if (connection_put(&backend->connection, &header, sizeof header) == -1 || - connection_put(&backend->connection, &msg, sizeof msg) == -1 || - connection_put(&backend->connection, path, pathlen) == -1 || dispatch(backend) == -1) { - return -1; - } - - size_t size = read_header(&backend->connection, SERVER_DEVICE_OPENED); - if (size == SIZE_MAX) { + if (conn_put(backend, &header, sizeof header) == -1 || + conn_put(backend, &msg, sizeof msg) == -1 || conn_put(backend, path, pathlen) == -1 || + dispatch(backend) == -1) { return -1; } struct proto_server_device_opened rmsg; - if (sizeof rmsg > size) { - goto badmsg_error; - } - if (connection_get(&backend->connection, &rmsg, sizeof rmsg) == -1) { - goto badmsg_error; + if (read_header(backend, SERVER_DEVICE_OPENED, sizeof rmsg, false) == SIZE_MAX || + conn_get(backend, &rmsg, sizeof rmsg) == -1 || conn_get_fd(backend, fd)) { + return -1; } - int received_fd = connection_get_fd(&backend->connection); - if (received_fd == -1) { - goto badmsg_error; - } - - *fd = received_fd; return rmsg.device_id; - -badmsg_error: - log_error("Received invalid message"); - errno = EBADMSG; - return -1; } static int close_device(struct libseat *base, int device_id) { @@ -432,34 +444,23 @@ static int close_device(struct libseat *base, int device_id) { .opcode = CLIENT_CLOSE_DEVICE, .size = sizeof msg, }; - - if (connection_put(&backend->connection, &header, sizeof header) == -1 || - connection_put(&backend->connection, &msg, sizeof msg) == -1 || dispatch(backend) == -1) { - return -1; - } - - size_t size = read_header(&backend->connection, SERVER_DEVICE_CLOSED); - if (size == SIZE_MAX) { + if (conn_put(backend, &header, sizeof header) == -1 || + conn_put(backend, &msg, sizeof msg) == -1 || dispatch(backend) == -1) { return -1; } struct proto_server_device_closed rmsg; - if (sizeof rmsg > size) { - goto badmsg_error; - } - if (connection_get(&backend->connection, &rmsg, sizeof rmsg) == -1) { - goto badmsg_error; + if (read_header(backend, SERVER_DEVICE_CLOSED, sizeof rmsg, false) == SIZE_MAX || + conn_get(backend, &rmsg, sizeof rmsg) == -1) { + return -1; } if (rmsg.device_id != device_id) { - goto badmsg_error; + log_errorf("Unexpected response: expected device close for %d, got device close for %d", + rmsg.device_id, device_id); + return -1; } return 0; - -badmsg_error: - log_error("Received invalid message"); - errno = EBADMSG; - return -1; } static int switch_session(struct libseat *base, int session) { @@ -475,10 +476,8 @@ static int switch_session(struct libseat *base, int session) { .opcode = CLIENT_SWITCH_SESSION, .size = sizeof msg, }; - - if (connection_put(&backend->connection, &header, sizeof header) == -1 || - connection_put(&backend->connection, &msg, sizeof msg) == -1 || - connection_flush(&backend->connection) == -1) { + if (conn_put(backend, &header, sizeof header) == -1 || + conn_put(backend, &msg, sizeof msg) == -1 || conn_flush(backend) == -1) { return -1; } @@ -491,9 +490,7 @@ static int disable_seat(struct libseat *base) { .opcode = CLIENT_DISABLE_SEAT, .size = 0, }; - - if (connection_put(&backend->connection, &header, sizeof header) == -1 || - connection_flush(&backend->connection) == -1) { + if (conn_put(backend, &header, sizeof header) == -1 || conn_flush(backend) == -1) { return -1; } From 98506d2ba44fcf9e3beddc880810f0c99b5bb8cb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 22:45:01 +0200 Subject: [PATCH 003/211] libseat: Keep track of error state Store if an error has occurred and return -1 with ENOTCONN from all future calls, avoiding attempts to use a broken connection. --- libseat/backend/seatd.c | 73 ++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 718838a..9172d65 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -36,6 +36,7 @@ struct backend_seatd { struct libseat_seat_listener *seat_listener; void *seat_listener_data; struct linked_list pending_events; + bool error; char seat_name[MAX_SEAT_LEN]; }; @@ -91,9 +92,37 @@ static struct backend_seatd *backend_seatd_from_libseat_backend(struct libseat * return (struct backend_seatd *)base; } +static void cleanup(struct backend_seatd *backend) { + if (backend->connection.fd != -1) { + close(backend->connection.fd); + backend->connection.fd = -1; + } + connection_close_fds(&backend->connection); + while (!linked_list_empty(&backend->pending_events)) { + struct pending_event *ev = (struct pending_event *)backend->pending_events.next; + linked_list_remove(&ev->link); + free(ev); + } +} + +static void destroy(struct backend_seatd *backend) { + cleanup(backend); + free(backend); +} + +static void set_error(struct backend_seatd *backend) { + if (backend->error) { + return; + } + + backend->error = true; + cleanup(backend); +} + static inline int conn_put(struct backend_seatd *backend, const void *data, const size_t data_len) { if (connection_put(&backend->connection, data, data_len) == -1) { log_errorf("Could not send request: %s", strerror(errno)); + set_error(backend); return -1; } return 0; @@ -102,6 +131,7 @@ static inline int conn_put(struct backend_seatd *backend, const void *data, cons static inline int conn_flush(struct backend_seatd *backend) { if (connection_flush(&backend->connection) == -1) { log_errorf("Could not flush connection: %s", strerror(errno)); + set_error(backend); return -1; } return 0; @@ -110,6 +140,7 @@ static inline int conn_flush(struct backend_seatd *backend) { static inline int conn_get(struct backend_seatd *backend, void *target, const size_t target_len) { if (connection_get(&backend->connection, target, target_len) == -1) { log_error("Invalid message: insufficient data received"); + set_error(backend); errno = EBADMSG; return -1; } @@ -119,6 +150,7 @@ static inline int conn_get(struct backend_seatd *backend, void *target, const si static inline int conn_get_fd(struct backend_seatd *backend, int *fd) { if (connection_get_fd(&backend->connection, fd) == -1) { log_error("Invalid message: insufficient data received"); + set_error(backend); errno = EBADMSG; return -1; } @@ -129,6 +161,7 @@ static size_t read_header(struct backend_seatd *backend, uint16_t expected_opcod size_t expected_size, bool variable) { struct proto_header header; if (conn_get(backend, &header, sizeof header) == -1) { + set_error(backend); return SIZE_MAX; } if (header.opcode != expected_opcode) { @@ -137,8 +170,10 @@ static size_t read_header(struct backend_seatd *backend, uint16_t expected_opcod if (header.opcode != SERVER_ERROR) { log_errorf("Unexpected response: expected opcode %d, received opcode %d", expected_opcode, header.opcode); + set_error(backend); errno = EBADMSG; } else if (conn_get(backend, &msg, sizeof msg) == -1) { + set_error(backend); errno = EBADMSG; } else { errno = msg.error_code; @@ -149,6 +184,7 @@ static size_t read_header(struct backend_seatd *backend, uint16_t expected_opcod if ((!variable && header.size != expected_size) || (variable && header.size < expected_size)) { log_errorf("Invalid message: does not match expected size: variable: %d, header.size: %d, expected size: %zd", variable, header.size, expected_size); + set_error(backend); errno = EBADMSG; return SIZE_MAX; } @@ -209,6 +245,7 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) { case SERVER_DISABLE_SEAT: case SERVER_ENABLE_SEAT: if (queue_event(backend, header.opcode) == -1) { + set_error(backend); return -1; } break; @@ -277,6 +314,11 @@ static int get_fd(struct libseat *base) { static int dispatch_background(struct libseat *base, int timeout) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); + if (backend->error) { + errno = ENOTCONN; + return -1; + } + int dispatched = dispatch_pending(backend, NULL); if (dispatched > 0) { // We don't want to block if we dispatched something, as the @@ -301,20 +343,6 @@ static int dispatch_background(struct libseat *base, int timeout) { return dispatched; } -static void destroy(struct backend_seatd *backend) { - if (backend->connection.fd != -1) { - close(backend->connection.fd); - backend->connection.fd = -1; - } - connection_close_fds(&backend->connection); - while (!linked_list_empty(&backend->pending_events)) { - struct pending_event *ev = (struct pending_event *)backend->pending_events.next; - linked_list_remove(&ev->link); - free(ev); - } - free(backend); -} - static struct libseat *_open_seat(struct libseat_seat_listener *listener, void *data, int fd) { assert(listener != NULL); assert(listener->enable_seat != NULL && listener->disable_seat != NULL); @@ -401,7 +429,10 @@ static const char *seat_name(struct libseat *base) { 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) { + errno = ENOTCONN; + return -1; + } size_t pathlen = strlen(path) + 1; if (pathlen > MAX_PATH_LEN) { errno = EINVAL; @@ -432,6 +463,10 @@ static int open_device(struct libseat *base, const char *path, int *fd) { static int close_device(struct libseat *base, int device_id) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); + if (backend->error) { + errno = ENOTCONN; + return -1; + } if (device_id < 0) { errno = EINVAL; return -1; @@ -465,6 +500,10 @@ static int close_device(struct libseat *base, int device_id) { static int switch_session(struct libseat *base, int session) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); + if (backend->error) { + errno = ENOTCONN; + return -1; + } if (session < 0) { return -1; } @@ -486,6 +525,10 @@ static int switch_session(struct libseat *base, int session) { static int disable_seat(struct libseat *base) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); + if (backend->error) { + errno = ENOTCONN; + return -1; + } struct proto_header header = { .opcode = CLIENT_DISABLE_SEAT, .size = 0, From 52fe75d5a404c390a1941b7f6cc3c18fb146ec3e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 22:55:17 +0200 Subject: [PATCH 004/211] libseat: Remove pointless check --- libseat/backend/seatd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 9172d65..5bb478e 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -489,11 +489,6 @@ static int close_device(struct libseat *base, int device_id) { conn_get(backend, &rmsg, sizeof rmsg) == -1) { return -1; } - if (rmsg.device_id != device_id) { - log_errorf("Unexpected response: expected device close for %d, got device close for %d", - rmsg.device_id, device_id); - return -1; - } return 0; } From 1ae6c3b3ddf0ce2a2e1817eb9c74e0c03153df58 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 22:58:00 +0200 Subject: [PATCH 005/211] libseat: Check euid before using builtin --- libseat/backend/seatd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 5bb478e..afeab7f 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -575,6 +575,11 @@ static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, return NULL; } + if (geteuid() != 0) { + log_debug("Built-in seatd instance requires root privileges"); + return NULL; + } + pid_t pid = fork(); if (pid == -1) { log_errorf("Could not fork: %s", strerror(errno)); From b7b28f06281efa162e1feaa20324012a0ed59dc4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 23:12:18 +0200 Subject: [PATCH 006/211] protocol: Add note to remove device_closed msg The content of this message is unused, so it should be converted to a content-less message. --- include/protocol.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/protocol.h b/include/protocol.h index 7444b85..b3250d0 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -51,8 +51,10 @@ struct proto_server_seat_opened { struct proto_server_device_opened { int device_id; + // One fd in auxillary data }; +// TODO: Content unused, remove before 0.3.0 struct proto_server_device_closed { int device_id; }; From 5470c481134ab194f32f53fd8d5ba7c916478f74 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 29 Aug 2020 23:49:22 +0200 Subject: [PATCH 007/211] seat: Destroy all clients on teardown --- include/client.h | 1 - seatd/client.c | 18 ++++-------------- seatd/seat.c | 3 +-- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/include/client.h b/include/client.h index e0d9016..75e4f46 100644 --- a/include/client.h +++ b/include/client.h @@ -28,7 +28,6 @@ struct client { }; struct client *client_create(struct server *server, int client_fd); -void client_kill(struct client *client); void client_destroy(struct client *client); int client_handle_connection(int fd, uint32_t mask, void *data); diff --git a/seatd/client.c b/seatd/client.c index 1adc2d9..0991fbb 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -72,19 +72,13 @@ struct client *client_create(struct server *server, int client_fd) { return client; } -void client_kill(struct client *client) { - assert(client); - if (client->connection.fd != -1) { - shutdown(client->connection.fd, SHUT_RDWR); - }; - if (client->seat != NULL) { - seat_remove_client(client); - } -} - void client_destroy(struct client *client) { assert(client); client->server = NULL; + if (client->connection.fd != -1) { + close(client->connection.fd); + client->connection.fd = -1; + } if (client->seat != NULL) { // This should also close and remove all devices seat_remove_client(client); @@ -93,10 +87,6 @@ void client_destroy(struct client *client) { event_source_fd_destroy(client->event_source); client->event_source = NULL; } - if (client->connection.fd != -1) { - close(client->connection.fd); - client->connection.fd = -1; - } connection_close_fds(&client->connection); assert(linked_list_empty(&client->devices)); free(client); diff --git a/seatd/seat.c b/seatd/seat.c index 40fbb09..fee727c 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -39,9 +39,8 @@ void seat_destroy(struct seat *seat) { assert(seat); while (!linked_list_empty(&seat->clients)) { struct client *client = (struct client *)seat->clients.next; - // This will cause the client to remove itself from the seat assert(client->seat == seat); - client_kill(client); + client_destroy(client); } assert(seat->curttyfd == -1); From c36cc962e6b3fd7bec8093756d4c3a7df9940862 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 30 Aug 2020 00:05:19 +0200 Subject: [PATCH 008/211] linked_list: Implement linked_list_take --- common/linked_list.c | 14 +++++++++++++ include/linked_list.h | 1 + libseat/backend/seatd.c | 10 ++-------- tests/linked_list.c | 44 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/common/linked_list.c b/common/linked_list.c index cb3e0a8..3d2ee7d 100644 --- a/common/linked_list.c +++ b/common/linked_list.c @@ -32,3 +32,17 @@ bool linked_list_empty(struct linked_list *list) { assert(list->prev != NULL && list->next != NULL); return list->next == list; } + +void linked_list_take(struct linked_list *target, struct linked_list *source) { + if (linked_list_empty(source)) { + linked_list_init(target); + return; + } + + target->next = source->next; + target->prev = source->prev; + target->next->prev = target; + target->prev->next = target; + + linked_list_init(source); +} diff --git a/include/linked_list.h b/include/linked_list.h index 47cf09b..7a20985 100644 --- a/include/linked_list.h +++ b/include/linked_list.h @@ -12,5 +12,6 @@ void linked_list_init(struct linked_list *list); void linked_list_insert(struct linked_list *list, struct linked_list *elem); void linked_list_remove(struct linked_list *elem); bool linked_list_empty(struct linked_list *list); +void linked_list_take(struct linked_list *target, struct linked_list *source); #endif diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index afeab7f..1a187b1 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -204,14 +204,8 @@ static int queue_event(struct backend_seatd *backend, int opcode) { } static void execute_events(struct backend_seatd *backend) { - struct linked_list list = { - .next = backend->pending_events.next, - .prev = backend->pending_events.prev, - }; - list.next->prev = &list; - list.prev->next = &list; - - linked_list_init(&backend->pending_events); + struct linked_list list; + linked_list_take(&list, &backend->pending_events); while (!linked_list_empty(&list)) { struct pending_event *ev = (struct pending_event *)list.next; int opcode = ev->opcode; diff --git a/tests/linked_list.c b/tests/linked_list.c index a5704a3..a29cff6 100644 --- a/tests/linked_list.c +++ b/tests/linked_list.c @@ -201,6 +201,47 @@ static void test_linked_list_loop_iterate(void) { assert(cnt == 3); } +static void test_linked_list_take_empty(void) { + struct linked_list list1, list2; + linked_list_init(&list1); + + linked_list_take(&list2, &list1); + + assert(linked_list_empty(&list1)); + assert(linked_list_empty(&list2)); +} + +static void test_linked_list_take_single(void) { + struct linked_list list1, list2; + linked_list_init(&list1); + + struct list_elem elem1 = {{0}, NULL}; + linked_list_insert(&list1, &elem1.link); + + linked_list_take(&list2, &list1); + + assert(linked_list_empty(&list1)); + assert(list2.next == &elem1.link && list2.prev == &elem1.link); + assert(elem1.link.next == &list2 && elem1.link.prev == &list2); +} + +static void test_linked_list_take_many(void) { + struct linked_list list1, list2; + linked_list_init(&list1); + + struct list_elem elem1 = {{0}, NULL}; + struct list_elem elem2 = {{0}, NULL}; + linked_list_insert(&list1, &elem2.link); + linked_list_insert(&list1, &elem1.link); + + linked_list_take(&list2, &list1); + + assert(linked_list_empty(&list1)); + assert(list2.next == &elem1.link && list2.prev == &elem2.link); + assert(elem1.link.next == &elem2.link && elem1.link.prev == &list2); + assert(elem2.link.next == &list2 && elem2.link.prev == &elem1.link); +} + int main(int argc, char *argv[]) { (void)argc; (void)argv; @@ -214,6 +255,9 @@ int main(int argc, char *argv[]) { test_linked_list_remove_loop(); test_linked_list_manual_iterate(); test_linked_list_loop_iterate(); + test_linked_list_take_empty(); + test_linked_list_take_single(); + test_linked_list_take_many(); return 0; } From e86c9ec2b722c8b6aef6ea90ecddb57081a1c67f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 30 Aug 2020 03:26:32 +0200 Subject: [PATCH 009/211] seatd: Remove unused device_closed msg body --- include/protocol.h | 5 ----- libseat/backend/seatd.c | 4 +--- seatd/client.c | 8 ++------ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/include/protocol.h b/include/protocol.h index b3250d0..b3361ba 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -54,11 +54,6 @@ struct proto_server_device_opened { // One fd in auxillary data }; -// TODO: Content unused, remove before 0.3.0 -struct proto_server_device_closed { - int device_id; -}; - struct proto_server_error { int error_code; }; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 1a187b1..46e354d 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -478,9 +478,7 @@ static int close_device(struct libseat *base, int device_id) { return -1; } - struct proto_server_device_closed rmsg; - if (read_header(backend, SERVER_DEVICE_CLOSED, sizeof rmsg, false) == SIZE_MAX || - conn_get(backend, &rmsg, sizeof rmsg) == -1) { + if (read_header(backend, SERVER_DEVICE_CLOSED, 0, false) == SIZE_MAX) { return -1; } diff --git a/seatd/client.c b/seatd/client.c index 0991fbb..dcb9456 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -250,16 +250,12 @@ static int handle_close_device(struct client *client, int device_id) { goto fail; } - struct proto_server_device_closed msg = { - .device_id = device_id, - }; struct proto_header header = { .opcode = SERVER_DEVICE_CLOSED, - .size = sizeof msg, + .size = 0, }; - if (connection_put(&client->connection, &header, sizeof header) == -1 || - connection_put(&client->connection, &msg, sizeof msg)) { + if (connection_put(&client->connection, &header, sizeof header) == -1) { log_errorf("unable to write response: %s", strerror(errno)); return -1; } From c9503ef35df3a5c4a0a34dcb937a84da47ff56ca Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 30 Aug 2020 03:26:52 +0200 Subject: [PATCH 010/211] seatd: Slight error handling cleanup --- seatd/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seatd/client.c b/seatd/client.c index dcb9456..87d6a91 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -112,7 +112,7 @@ static int client_send_error(struct client *client, int error_code) { }; if (connection_put(&client->connection, &errheader, sizeof errheader) == -1 || - connection_put(&client->connection, &errmsg, sizeof errmsg)) { + connection_put(&client->connection, &errmsg, sizeof errmsg) == -1) { log_error("could not send error to client"); return -1; } @@ -221,7 +221,7 @@ static int handle_open_device(struct client *client, char *path) { }; if (connection_put(&client->connection, &header, sizeof header) == -1 || - connection_put(&client->connection, &msg, sizeof msg)) { + connection_put(&client->connection, &msg, sizeof msg) == -1) { log_errorf("unable to write response: %s", strerror(errno)); return -1; } From 8e1bf10d9decab347455b3036143b21d7f90d390 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 30 Aug 2020 23:16:47 +0200 Subject: [PATCH 011/211] seatd: Explicit cast -1 to unsigned gid_t Silences a warning on some architectures. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 87d6a91..d658454 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -42,7 +42,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { } *pid = -1; *uid = cred.cr_uid; - *gid = cred.cr_ngroups > 0 ? cred.cr_groups[0] : -1; + *gid = cred.cr_ngroups > 0 ? cred.cr_groups[0] : (gid_t)-1; return 0; #else return -1; From 7d88315fea1448fc3f0e33c7a8a00ec12458b473 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 01:33:41 +0200 Subject: [PATCH 012/211] poller: Make event sources opaque --- include/poller.h | 74 +++++++++++++++--------------------------------- seatd/poller.c | 24 ++++++++++++++++ 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/include/poller.h b/include/poller.h index 6b727c4..0142add 100644 --- a/include/poller.h +++ b/include/poller.h @@ -6,10 +6,6 @@ #include "list.h" -struct poller; -struct event_source_fd; -struct event_source_signal; - /* * These are the event types available from the poller. */ @@ -18,6 +14,16 @@ struct event_source_signal; #define EVENT_ERROR 0x8 #define EVENT_HANGUP 0x10 +/** + * The fd poller class. This must be created by poller_add_fd. + */ +struct event_source_fd; + +/* + * The signal poller class. This must be created by poller_add_signal. + */ +struct event_source_signal; + /** * The callback type used by event_source_fd, passed to poller_add_fd. */ @@ -31,21 +37,6 @@ struct event_source_fd_impl { int (*destroy)(struct event_source_fd *event_source); }; -/** - * The fd poller class. This must be created by poller_add_fd. - */ -struct event_source_fd { - const struct event_source_fd_impl *impl; - event_source_fd_func_t func; - - int fd; - uint32_t mask; - void *data; - - struct poller *poller; - bool killed; -}; - /** * Removes the event_source_fd from the poller and frees the structure. */ @@ -68,41 +59,11 @@ struct event_source_signal_impl { int (*destroy)(struct event_source_signal *event_source); }; -/* - * The signal poller class. This must be created by poller_add_signal. - */ -struct event_source_signal { - const struct event_source_signal_impl *impl; - event_source_signal_func_t func; - - int signal; - void *data; - - struct poller *poller; - bool raised; - bool killed; -}; - /** * Removes the event_source_siganl from the poller and frees the structure. */ int event_source_signal_destroy(struct event_source_signal *event_source); -/** - * The interface that a poll backend must implement. - */ -struct poll_impl { - struct poller *(*create)(void); - int (*destroy)(struct poller *); - - struct event_source_fd *(*add_fd)(struct poller *, int fd, uint32_t mask, - event_source_fd_func_t func, void *data); - struct event_source_signal *(*add_signal)(struct poller *, int signal, - event_source_signal_func_t func, void *data); - - int (*poll)(struct poller *); -}; - /** * The poller base class. This must be created by poller_create. */ @@ -119,9 +80,20 @@ struct poller { }; /** - * Creates a poller with the best available polling backend. This poller must - * be torn down with poller_destroy when it is no longer needed. + * The interface that a poll backend must implement. */ +struct poll_impl { + struct poller *(*create)(void); + int (*destroy)(struct poller *); + + struct event_source_fd *(*add_fd)(struct poller *, int fd, uint32_t mask, + event_source_fd_func_t func, void *data); + struct event_source_signal *(*add_signal)(struct poller *, int signal, + event_source_signal_func_t func, void *data); + + int (*poll)(struct poller *); +}; + /** * Initializes the poller. The poller must be torn down with poller_finish when * it is no longer needed. diff --git a/seatd/poller.c b/seatd/poller.c index f786d47..0631f4b 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -10,6 +10,30 @@ #include "list.h" #include "poller.h" +struct event_source_fd { + const struct event_source_fd_impl *impl; + event_source_fd_func_t func; + + int fd; + uint32_t mask; + void *data; + + struct poller *poller; + bool killed; +}; + +struct event_source_signal { + const struct event_source_signal_impl *impl; + event_source_signal_func_t func; + + int signal; + void *data; + + struct poller *poller; + bool raised; + bool killed; +}; + /* Used for signal handling */ struct poller *global_poller = NULL; From d75b617fafa41b83aab5943827224df8b7ff9e4a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 01:34:36 +0200 Subject: [PATCH 013/211] server: Convert seat list to linked_list --- include/seat.h | 1 + include/server.h | 4 ++-- seatd/server.c | 15 +++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/seat.h b/include/seat.h index 60d3b29..30f7cc4 100644 --- a/include/seat.h +++ b/include/seat.h @@ -26,6 +26,7 @@ struct seat_device { }; struct seat { + struct linked_list link; // server::seats char *seat_name; struct linked_list clients; struct client *active_client; diff --git a/include/server.h b/include/server.h index a225668..587047e 100644 --- a/include/server.h +++ b/include/server.h @@ -3,7 +3,7 @@ #include -#include "list.h" +#include "linked_list.h" #include "poller.h" struct client; @@ -12,7 +12,7 @@ struct server { bool running; struct poller poller; - struct list seats; + struct linked_list seats; }; int server_init(struct server *server); diff --git a/seatd/server.c b/seatd/server.c index 7368ea3..4562a71 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -12,7 +12,6 @@ #include #include "client.h" -#include "list.h" #include "log.h" #include "poller.h" #include "seat.h" @@ -26,7 +25,7 @@ static int server_handle_kill(int signal, void *data); int server_init(struct server *server) { poller_init(&server->poller); - list_init(&server->seats); + linked_list_init(&server->seats); if (poller_add_signal(&server->poller, SIGUSR1, server_handle_vt_rel, server) == NULL || poller_add_signal(&server->poller, SIGUSR2, server_handle_vt_acq, server) == NULL || @@ -45,24 +44,24 @@ int server_init(struct server *server) { return -1; } - list_add(&server->seats, seat); + linked_list_insert(&server->seats, &seat->link); server->running = true; return 0; } void server_finish(struct server *server) { assert(server); - for (size_t idx = 0; idx < server->seats.length; idx++) { - struct seat *seat = server->seats.items[idx]; + while (!linked_list_empty(&server->seats)) { + struct seat *seat = (struct seat *)server->seats.next; seat_destroy(seat); } - list_free(&server->seats); poller_finish(&server->poller); } struct seat *server_get_seat(struct server *server, const char *seat_name) { - for (size_t idx = 0; idx < server->seats.length; idx++) { - struct seat *seat = server->seats.items[idx]; + for (struct linked_list *elem = server->seats.next; elem != &server->seats; + elem = elem->next) { + struct seat *seat = (struct seat *)elem; if (strcmp(seat->seat_name, seat_name) == 0) { return seat; } From bbfb770c73498413055c7af8d3e1b8db36560016 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 02:26:47 +0200 Subject: [PATCH 014/211] linked_list: linked_list_take should concat lists --- common/linked_list.c | 8 +++----- libseat/backend/seatd.c | 1 + tests/linked_list.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/common/linked_list.c b/common/linked_list.c index 3d2ee7d..7383de0 100644 --- a/common/linked_list.c +++ b/common/linked_list.c @@ -35,14 +35,12 @@ bool linked_list_empty(struct linked_list *list) { void linked_list_take(struct linked_list *target, struct linked_list *source) { if (linked_list_empty(source)) { - linked_list_init(target); return; } + source->next->prev = target; + source->prev->next = target->next; + target->next->prev = source->prev; target->next = source->next; - target->prev = source->prev; - target->next->prev = target; - target->prev->next = target; - linked_list_init(source); } diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 46e354d..400b357 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -205,6 +205,7 @@ static int queue_event(struct backend_seatd *backend, int opcode) { static void execute_events(struct backend_seatd *backend) { struct linked_list list; + linked_list_init(&list); linked_list_take(&list, &backend->pending_events); while (!linked_list_empty(&list)) { struct pending_event *ev = (struct pending_event *)list.next; diff --git a/tests/linked_list.c b/tests/linked_list.c index a29cff6..71322b8 100644 --- a/tests/linked_list.c +++ b/tests/linked_list.c @@ -204,6 +204,7 @@ static void test_linked_list_loop_iterate(void) { static void test_linked_list_take_empty(void) { struct linked_list list1, list2; linked_list_init(&list1); + linked_list_init(&list2); linked_list_take(&list2, &list1); @@ -214,6 +215,7 @@ static void test_linked_list_take_empty(void) { static void test_linked_list_take_single(void) { struct linked_list list1, list2; linked_list_init(&list1); + linked_list_init(&list2); struct list_elem elem1 = {{0}, NULL}; linked_list_insert(&list1, &elem1.link); @@ -228,6 +230,7 @@ static void test_linked_list_take_single(void) { static void test_linked_list_take_many(void) { struct linked_list list1, list2; linked_list_init(&list1); + linked_list_init(&list2); struct list_elem elem1 = {{0}, NULL}; struct list_elem elem2 = {{0}, NULL}; @@ -242,6 +245,30 @@ static void test_linked_list_take_many(void) { assert(elem2.link.next == &list2 && elem2.link.prev == &elem1.link); } +static void test_linked_list_take_concat(void) { + struct linked_list list1, list2; + linked_list_init(&list1); + linked_list_init(&list2); + + struct list_elem elem1 = {{0}, NULL}; + struct list_elem elem2 = {{0}, NULL}; + struct list_elem elem3 = {{0}, NULL}; + struct list_elem elem4 = {{0}, NULL}; + linked_list_insert(&list1, &elem2.link); + linked_list_insert(&list1, &elem1.link); + linked_list_insert(&list2, &elem4.link); + linked_list_insert(&list2, &elem3.link); + + linked_list_take(&list2, &list1); + + assert(linked_list_empty(&list1)); + assert(list2.next == &elem1.link && list2.prev == &elem4.link); + assert(elem1.link.next == &elem2.link && elem1.link.prev == &list2); + assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); + assert(elem3.link.next == &elem4.link && elem3.link.prev == &elem2.link); + assert(elem4.link.next == &list2 && elem4.link.prev == &elem3.link); +} + int main(int argc, char *argv[]) { (void)argc; (void)argv; @@ -258,6 +285,7 @@ int main(int argc, char *argv[]) { test_linked_list_take_empty(); test_linked_list_take_single(); test_linked_list_take_many(); + test_linked_list_take_concat(); return 0; } From d17632fadd1f901aa1fd41aceb06663019d73ade Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 03:14:51 +0200 Subject: [PATCH 015/211] poller: Convert to linked_list --- include/poller.h | 12 ++- seatd/poller.c | 203 +++++++++++++++++------------------------------ 2 files changed, 79 insertions(+), 136 deletions(-) diff --git a/include/poller.h b/include/poller.h index 0142add..f30bbda 100644 --- a/include/poller.h +++ b/include/poller.h @@ -4,7 +4,7 @@ #include #include -#include "list.h" +#include "linked_list.h" /* * These are the event types available from the poller. @@ -68,15 +68,13 @@ int event_source_signal_destroy(struct event_source_signal *event_source); * The poller base class. This must be created by poller_create. */ struct poller { - struct list signals; - struct list new_signals; - struct list fds; - struct list new_fds; + struct linked_list signals; + struct linked_list fds; struct pollfd *pollfds; size_t pollfds_len; - bool dirty; - bool inpoll; + size_t fd_event_sources; + bool pollfds_dirty; }; /** diff --git a/seatd/poller.c b/seatd/poller.c index 0631f4b..74d5d89 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -6,11 +6,13 @@ #include #include #include +#include -#include "list.h" +#include "linked_list.h" #include "poller.h" struct event_source_fd { + struct linked_list link; // poller::fds const struct event_source_fd_impl *impl; event_source_fd_func_t func; @@ -20,9 +22,11 @@ struct event_source_fd { struct poller *poller; bool killed; + ssize_t pollfd_idx; }; struct event_source_signal { + struct linked_list link; // poller::signals const struct event_source_signal_impl *impl; event_source_signal_func_t func; @@ -40,26 +44,21 @@ struct poller *global_poller = NULL; void poller_init(struct poller *poller) { assert(global_poller == NULL); - list_init(&poller->fds); - list_init(&poller->new_fds); - list_init(&poller->signals); - list_init(&poller->new_signals); + linked_list_init(&poller->fds); + linked_list_init(&poller->signals); + poller->pollfds = NULL; + poller->pollfds_len = 0; + poller->fd_event_sources = 0; global_poller = poller; } int poller_finish(struct poller *poller) { - for (size_t idx = 0; idx < poller->fds.length; idx++) { - struct event_source_fd *bpfd = poller->fds.items[idx]; + while (!linked_list_empty(&poller->fds)) { + struct event_source_fd *bpfd = (struct event_source_fd *)poller->fds.next; free(bpfd); } - list_free(&poller->fds); - for (size_t idx = 0; idx < poller->new_fds.length; idx++) { - struct event_source_fd *bpfd = poller->new_fds.items[idx]; - free(bpfd); - } - list_free(&poller->new_fds); - for (size_t idx = 0; idx < poller->signals.length; idx++) { - struct event_source_signal *bps = poller->signals.items[idx]; + while (!linked_list_empty(&poller->signals)) { + struct event_source_signal *bps = (struct event_source_signal *)poller->signals.next; struct sigaction sa; sa.sa_handler = SIG_DFL; @@ -69,19 +68,6 @@ int poller_finish(struct poller *poller) { free(bps); } - list_free(&poller->signals); - for (size_t idx = 0; idx < poller->new_signals.length; idx++) { - struct event_source_signal *bps = poller->new_signals.items[idx]; - - struct sigaction sa; - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(bps->signal, &sa, NULL); - - free(bps); - } - list_free(&poller->new_signals); free(poller->pollfds); return 0; } @@ -115,24 +101,31 @@ static uint32_t poll_mask_to_event_mask(int poll_mask) { } static int regenerate_pollfds(struct poller *poller) { - if (poller->pollfds_len != poller->fds.length) { - struct pollfd *fds = calloc(poller->fds.length, sizeof(struct pollfd)); + if (!poller->pollfds_dirty) { + return 0; + } + + if (poller->fd_event_sources > poller->pollfds_len) { + struct pollfd *fds = calloc(poller->fd_event_sources, sizeof(struct pollfd)); if (fds == NULL) { return -1; } free(poller->pollfds); poller->pollfds = fds; - poller->pollfds_len = poller->fds.length; + poller->pollfds_len = poller->fd_event_sources; } - for (size_t idx = 0; idx < poller->fds.length; idx++) { - struct event_source_fd *bpfd = poller->fds.items[idx]; - poller->pollfds[idx] = (struct pollfd){ + ssize_t idx = 0; + for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { + struct event_source_fd *bpfd = (struct event_source_fd *)elem; + bpfd->pollfd_idx = idx++; + poller->pollfds[bpfd->pollfd_idx] = (struct pollfd){ .fd = bpfd->fd, .events = event_mask_to_poll_mask(bpfd->mask), }; } + poller->pollfds_dirty = false; return 0; } @@ -147,31 +140,19 @@ struct event_source_fd *poller_add_fd(struct poller *poller, int fd, uint32_t ma bpfd->data = data; bpfd->func = func; bpfd->poller = poller; - poller->dirty = true; - if (poller->inpoll) { - list_add(&poller->new_fds, bpfd); - } else { - list_add(&poller->fds, bpfd); - regenerate_pollfds(poller); - } + bpfd->pollfd_idx = -1; + poller->fd_event_sources += 1; + poller->pollfds_dirty = true; + linked_list_insert(&poller->fds, &bpfd->link); return (struct event_source_fd *)bpfd; } int event_source_fd_destroy(struct event_source_fd *event_source) { struct event_source_fd *bpfd = (struct event_source_fd *)event_source; struct poller *poller = bpfd->poller; - int idx = list_find(&poller->fds, event_source); - if (idx == -1) { - return -1; - } - poller->dirty = true; - if (poller->inpoll) { - bpfd->killed = true; - } else { - list_del(&poller->fds, idx); - free(bpfd); - regenerate_pollfds(poller); - } + poller->fd_event_sources -= 1; + poller->pollfds_dirty = true; + bpfd->killed = true; return 0; } @@ -179,11 +160,7 @@ int event_source_fd_update(struct event_source_fd *event_source, uint32_t mask) struct event_source_fd *bpfd = (struct event_source_fd *)event_source; struct poller *poller = bpfd->poller; event_source->mask = mask; - - poller->dirty = true; - if (!poller->inpoll) { - regenerate_pollfds(poller); - } + poller->pollfds_dirty = true; return 0; } @@ -191,9 +168,9 @@ static void signal_handler(int sig) { if (global_poller == NULL) { return; } - - for (size_t idx = 0; idx < global_poller->signals.length; idx++) { - struct event_source_signal *bps = global_poller->signals.items[idx]; + for (struct linked_list *elem = global_poller->signals.next; + elem != &global_poller->signals; elem = elem->next) { + struct event_source_signal *bps = (struct event_source_signal *)elem; if (bps->signal == sig) { bps->raised = true; } @@ -208,32 +185,18 @@ struct event_source_signal *poller_add_signal(struct poller *poller, int signal, return NULL; } - int refcnt = 0; - for (size_t idx = 0; idx < poller->signals.length; idx++) { - struct event_source_signal *bps = poller->signals.items[idx]; - if (bps->signal == signal) { - refcnt++; - } - } - bps->signal = signal; bps->data = data; bps->func = func; bps->poller = poller; - if (refcnt == 0) { - struct sigaction sa; - sa.sa_handler = &signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(signal, &sa, NULL); - } + struct sigaction sa; + sa.sa_handler = &signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(signal, &sa, NULL); - if (poller->inpoll) { - list_add(&poller->new_signals, bps); - } else { - list_add(&poller->signals, bps); - } + linked_list_insert(&poller->signals, &bps->link); return (struct event_source_signal *)bps; } @@ -242,15 +205,11 @@ int event_source_signal_destroy(struct event_source_signal *event_source) { struct event_source_signal *bps = (struct event_source_signal *)event_source; struct poller *poller = bps->poller; - int idx = list_find(&poller->signals, event_source); - if (idx == -1) { - return -1; - } - int refcnt = 0; - for (size_t idx = 0; idx < poller->signals.length; idx++) { - struct event_source_signal *b = poller->signals.items[idx]; - if (b->signal == bps->signal) { + for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; + elem = elem->next) { + struct event_source_signal *b = (struct event_source_signal *)elem; + if (b->signal == bps->signal && !b->killed) { refcnt++; } } @@ -263,77 +222,63 @@ int event_source_signal_destroy(struct event_source_signal *event_source) { sigaction(bps->signal, &sa, NULL); } - if (poller->inpoll) { - bps->killed = true; - } else { - list_del(&poller->signals, idx); - free(bps); - } + bps->killed = true; return 0; } int poller_poll(struct poller *poller) { - if (poll(poller->pollfds, poller->fds.length, -1) == -1 && errno != EINTR) { + if (regenerate_pollfds(poller) == -1) { return -1; } - poller->inpoll = true; + if (poll(poller->pollfds, poller->fd_event_sources, -1) == -1 && errno != EINTR) { + return -1; + } - for (size_t idx = 0; idx < poller->fds.length; idx++) { - short revents = poller->pollfds[idx].revents; + for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { + struct event_source_fd *bpfd = (struct event_source_fd *)elem; + if (bpfd->pollfd_idx == -1 || bpfd->killed) { + continue; + } + short revents = poller->pollfds[bpfd->pollfd_idx].revents; if (revents == 0) { continue; } - struct event_source_fd *bpfd = poller->fds.items[idx]; - bpfd->func(poller->pollfds[idx].fd, poll_mask_to_event_mask(revents), bpfd->data); + bpfd->func(poller->pollfds[bpfd->pollfd_idx].fd, poll_mask_to_event_mask(revents), + bpfd->data); } - for (size_t idx = 0; idx < poller->signals.length; idx++) { - struct event_source_signal *bps = poller->signals.items[idx]; - if (!bps->raised) { + for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; + elem = elem->next) { + struct event_source_signal *bps = (struct event_source_signal *)elem; + if (!bps->raised || bps->killed) { continue; } bps->func(bps->signal, bps->data); bps->raised = false; } - poller->inpoll = false; - - for (size_t idx = 0; idx < poller->fds.length; idx++) { - struct event_source_fd *bpfd = poller->fds.items[idx]; + for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { + struct event_source_fd *bpfd = (struct event_source_fd *)elem; if (!bpfd->killed) { continue; } - list_del(&poller->fds, idx); + elem = elem->prev; + linked_list_remove(&bpfd->link); free(bpfd); - idx--; } - for (size_t idx = 0; idx < poller->signals.length; idx++) { - struct event_source_signal *bps = poller->signals.items[idx]; + for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; + elem = elem->next) { + struct event_source_signal *bps = (struct event_source_signal *)elem; if (!bps->killed) { continue; } - list_del(&poller->signals, idx); + elem = elem->prev; + linked_list_remove(&bps->link); free(bps); - idx--; - } - - if (poller->new_fds.length > 0) { - list_concat(&poller->fds, &poller->new_fds); - list_truncate(&poller->new_fds); - } - - if (poller->new_signals.length > 0) { - list_concat(&poller->signals, &poller->new_signals); - list_truncate(&poller->new_signals); - } - - if (poller->dirty) { - regenerate_pollfds(poller); - poller->dirty = false; } return 0; From 8610ec4aac6027e702d0aaea0331ccaa41489834 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 14:13:29 +0200 Subject: [PATCH 016/211] Remove unused list implementation --- common/list.c | 85 -------------------------------------------------- include/list.h | 23 -------------- meson.build | 1 - 3 files changed, 109 deletions(-) delete mode 100644 common/list.c delete mode 100644 include/list.h diff --git a/common/list.c b/common/list.c deleted file mode 100644 index 557e0dc..0000000 --- a/common/list.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include - -#include "list.h" - -void list_init(struct list *list) { - list->capacity = 10; - list->length = 0; - list->items = malloc(sizeof(void *) * list->capacity); -} - -static void list_resize(struct list *list) { - if (list->length == list->capacity) { - list->capacity *= 2; - list->items = realloc(list->items, sizeof(void *) * list->capacity); - } -} - -void list_free(struct list *list) { - list->capacity = 0; - list->length = 0; - free(list->items); -} - -void list_add(struct list *list, void *item) { - list_resize(list); - list->items[list->length++] = item; -} - -void list_insert(struct list *list, size_t index, void *item) { - list_resize(list); - memmove(&list->items[index + 1], &list->items[index], - sizeof(void *) * (list->length - index)); - list->length++; - list->items[index] = item; -} - -void list_del(struct list *list, size_t index) { - list->length--; - memmove(&list->items[index], &list->items[index + 1], - sizeof(void *) * (list->length - index)); -} - -size_t list_find(struct list *list, const void *item) { - for (size_t i = 0; i < list->length; i++) { - if (list->items[i] == item) { - return i; - } - } - return -1; -} - -void list_concat(struct list *list, const struct list *source) { - if (list->length + source->length > list->capacity) { - while (list->length + source->length > list->capacity) { - list->capacity *= 2; - } - list->items = realloc(list->items, sizeof(void *) * list->capacity); - } - memmove(&list->items[list->length], source->items, sizeof(void *) * (source->length)); - list->length += source->length; -} - -void list_truncate(struct list *list) { - list->length = 0; -} - -void *list_pop_front(struct list *list) { - if (list->length == 0) { - return NULL; - } - void *item = list->items[0]; - list_del(list, 0); - return item; -} - -void *list_pop_back(struct list *list) { - if (list->length == 0) { - return NULL; - } - void *item = list->items[list->length - 1]; - list->length -= 1; - return item; -} diff --git a/include/list.h b/include/list.h deleted file mode 100644 index 012f216..0000000 --- a/include/list.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SEATD_LIST_H -#define _SEATD_LIST_H - -#include - -struct list { - size_t capacity; - size_t length; - void **items; -}; - -void list_init(struct list *); -void list_free(struct list *list); -void list_add(struct list *list, void *item); -void list_insert(struct list *list, size_t index, void *item); -void list_del(struct list *list, size_t index); -void list_concat(struct list *list, const struct list *source); -void list_truncate(struct list *list); -void *list_pop_front(struct list *list); -void *list_pop_back(struct list *list); -size_t list_find(struct list *list, const void *item); - -#endif diff --git a/meson.build b/meson.build index 301b0e3..bc167e8 100644 --- a/meson.build +++ b/meson.build @@ -81,7 +81,6 @@ private_deps = [] server_files = [ 'common/log.c', 'common/linked_list.c', - 'common/list.c', 'common/terminal.c', 'common/connection.c', 'common/evdev.c', From aef19fe383a70f47fa83a70cfce70fa4a713c1d1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 14:30:28 +0200 Subject: [PATCH 017/211] test: Add test_run and test_assert macros test_run and test_assert replaces regular assert with better logging which include the currently running test name. The tests can now also be built without DEBUG. --- include/test.h | 23 +++++++ tests/linked_list.c | 146 ++++++++++++++++++++++---------------------- 2 files changed, 96 insertions(+), 73 deletions(-) create mode 100644 include/test.h diff --git a/include/test.h b/include/test.h new file mode 100644 index 0000000..64716cc --- /dev/null +++ b/include/test.h @@ -0,0 +1,23 @@ +#ifndef _TEST_H +#define _TEST_H + +char *__curtestname = ""; + +#define test_run(func) \ + do { \ + char *orig = __curtestname; \ + __curtestname = #func; \ + func(); \ + __curtestname = orig; \ + } while (0) + +#define test_assert(cond) \ + do { \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: %s: test_assert failed: %s\n", __FILE__, __LINE__, \ + __curtestname, #cond); \ + abort(); \ + } \ + } while (0) + +#endif diff --git a/tests/linked_list.c b/tests/linked_list.c index 71322b8..6d7a995 100644 --- a/tests/linked_list.c +++ b/tests/linked_list.c @@ -1,9 +1,9 @@ -#include #include #include #include #include "linked_list.h" +#include "test.h" struct list_elem { struct linked_list link; @@ -15,10 +15,10 @@ static void test_linked_list_init(void) { linked_list_init(&list); // Both next and prev should point to self - assert(list.next == &list && list.prev == &list); + test_assert(list.next == &list && list.prev == &list); // The list should be empty - assert(linked_list_empty(&list)); + test_assert(linked_list_empty(&list)); } static void test_linked_list_single_insert(void) { @@ -29,14 +29,14 @@ static void test_linked_list_single_insert(void) { linked_list_insert(&list, &elem1.link); // Both next and prev on list should point to the elem - assert(list.next == &elem1.link && list.prev == &elem1.link); + test_assert(list.next == &elem1.link && list.prev == &elem1.link); // Both next and prev on elem should point to the list - assert(elem1.link.next == &list && elem1.link.prev == &list); + test_assert(elem1.link.next == &list && elem1.link.prev == &list); // The list and element should not be empty - assert(!linked_list_empty(&list)); - assert(!linked_list_empty(&elem1.link)); + test_assert(!linked_list_empty(&list)); + test_assert(!linked_list_empty(&elem1.link)); } static void test_linked_list_single_remove(void) { @@ -48,13 +48,13 @@ static void test_linked_list_single_remove(void) { linked_list_remove(&elem1.link); // Both next and prev on elem be NULL - assert(elem1.link.next == NULL && elem1.link.prev == NULL); + test_assert(elem1.link.next == NULL && elem1.link.prev == NULL); // Both next and prev should point to self - assert(list.next == &list && list.prev == &list); + test_assert(list.next == &list && list.prev == &list); // The list should be empty - assert(linked_list_empty(&list)); + test_assert(linked_list_empty(&list)); } static void test_linked_list_alternate_remove(void) { @@ -66,13 +66,13 @@ static void test_linked_list_alternate_remove(void) { linked_list_remove(&list); // Both next and prev on list be NULL - assert(list.next == NULL && list.prev == NULL); + test_assert(list.next == NULL && list.prev == NULL); // Both next and prev should point to self - assert(elem1.link.next == &elem1.link && elem1.link.prev == &elem1.link); + test_assert(elem1.link.next == &elem1.link && elem1.link.prev == &elem1.link); // The elem should be empty - assert(linked_list_empty(&elem1.link)); + test_assert(linked_list_empty(&elem1.link)); } static void test_linked_list_sequential_remove(void) { @@ -85,35 +85,35 @@ static void test_linked_list_sequential_remove(void) { linked_list_insert(&elem2.link, &elem3.link); // The order should now be list→elem1→elem2→elem3→list - assert(list.next == &elem1.link && list.prev == &elem3.link); - assert(elem1.link.next == &elem2.link && elem1.link.prev == &list); - assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); - assert(elem3.link.next == &list && elem3.link.prev == &elem2.link); + test_assert(list.next == &elem1.link && list.prev == &elem3.link); + test_assert(elem1.link.next == &elem2.link && elem1.link.prev == &list); + test_assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); + test_assert(elem3.link.next == &list && elem3.link.prev == &elem2.link); linked_list_remove(list.next); // The order should now be list→elem2→elem3→list - assert(list.next == &elem2.link && list.prev == &elem3.link); - assert(elem2.link.next == &elem3.link && elem2.link.prev == &list); - assert(elem3.link.next == &list && elem3.link.prev == &elem2.link); - assert(elem1.link.next == NULL && elem1.link.prev == NULL); + test_assert(list.next == &elem2.link && list.prev == &elem3.link); + test_assert(elem2.link.next == &elem3.link && elem2.link.prev == &list); + test_assert(elem3.link.next == &list && elem3.link.prev == &elem2.link); + test_assert(elem1.link.next == NULL && elem1.link.prev == NULL); linked_list_remove(list.next); // The order should now be list→elem3→list - assert(list.next == &elem3.link && list.prev == &elem3.link); - assert(elem3.link.next == &list && elem3.link.prev == &list); - assert(elem1.link.next == NULL && elem1.link.prev == NULL); - assert(elem2.link.next == NULL && elem2.link.prev == NULL); + test_assert(list.next == &elem3.link && list.prev == &elem3.link); + test_assert(elem3.link.next == &list && elem3.link.prev == &list); + test_assert(elem1.link.next == NULL && elem1.link.prev == NULL); + test_assert(elem2.link.next == NULL && elem2.link.prev == NULL); linked_list_remove(list.next); // The list should now be empty - assert(elem1.link.next == NULL && elem1.link.prev == NULL); - assert(elem2.link.next == NULL && elem2.link.prev == NULL); - assert(elem3.link.next == NULL && elem3.link.prev == NULL); - assert(list.next == &list && list.prev == &list); - assert(linked_list_empty(&list)); + test_assert(elem1.link.next == NULL && elem1.link.prev == NULL); + test_assert(elem2.link.next == NULL && elem2.link.prev == NULL); + test_assert(elem3.link.next == NULL && elem3.link.prev == NULL); + test_assert(list.next == &list && list.prev == &list); + test_assert(linked_list_empty(&list)); } static void test_linked_list_insert_after(void) { @@ -126,10 +126,10 @@ static void test_linked_list_insert_after(void) { linked_list_insert(&elem1.link, &elem2.link); // The order should now be list→elem1→elem2→elem3→list - assert(list.next == &elem1.link && list.prev == &elem3.link); - assert(elem1.link.next == &elem2.link && elem1.link.prev == &list); - assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); - assert(elem3.link.next == &list && elem3.link.prev == &elem2.link); + test_assert(list.next == &elem1.link && list.prev == &elem3.link); + test_assert(elem1.link.next == &elem2.link && elem1.link.prev == &list); + test_assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); + test_assert(elem3.link.next == &list && elem3.link.prev == &elem2.link); } static void test_linked_list_remove_loop(void) { @@ -147,13 +147,13 @@ static void test_linked_list_remove_loop(void) { linked_list_remove(&elem->link); cnt++; } - assert(cnt == 3); + test_assert(cnt == 3); // Link should now be empty, and next and prev on all elements hsould be NULL - assert(linked_list_empty(&list)); - assert(elem1.link.next == NULL && elem1.link.prev == NULL); - assert(elem2.link.next == NULL && elem2.link.prev == NULL); - assert(elem3.link.next == NULL && elem3.link.prev == NULL); + test_assert(linked_list_empty(&list)); + test_assert(elem1.link.next == NULL && elem1.link.prev == NULL); + test_assert(elem2.link.next == NULL && elem2.link.prev == NULL); + test_assert(elem3.link.next == NULL && elem3.link.prev == NULL); } static void test_linked_list_manual_iterate(void) { @@ -170,15 +170,15 @@ static void test_linked_list_manual_iterate(void) { struct list_elem *ptr = NULL; ptr = (struct list_elem *)list.next; - assert(strcmp("elem1", ptr->content) == 0); + test_assert(strcmp("elem1", ptr->content) == 0); ptr = (struct list_elem *)ptr->link.next; - assert(strcmp("elem2", ptr->content) == 0); + test_assert(strcmp("elem2", ptr->content) == 0); ptr = (struct list_elem *)ptr->link.next; - assert(strcmp("elem3", ptr->content) == 0); + test_assert(strcmp("elem3", ptr->content) == 0); - assert(ptr->link.next == &list); + test_assert(ptr->link.next == &list); } static void test_linked_list_loop_iterate(void) { @@ -195,10 +195,10 @@ static void test_linked_list_loop_iterate(void) { size_t cnt = 0; for (struct linked_list *ptr = list.next; ptr != &list; ptr = ptr->next) { struct list_elem *elem = (struct list_elem *)ptr; - assert(strcmp("elem", elem->content) == 0); + test_assert(strcmp("elem", elem->content) == 0); cnt++; } - assert(cnt == 3); + test_assert(cnt == 3); } static void test_linked_list_take_empty(void) { @@ -208,8 +208,8 @@ static void test_linked_list_take_empty(void) { linked_list_take(&list2, &list1); - assert(linked_list_empty(&list1)); - assert(linked_list_empty(&list2)); + test_assert(linked_list_empty(&list1)); + test_assert(linked_list_empty(&list2)); } static void test_linked_list_take_single(void) { @@ -222,9 +222,9 @@ static void test_linked_list_take_single(void) { linked_list_take(&list2, &list1); - assert(linked_list_empty(&list1)); - assert(list2.next == &elem1.link && list2.prev == &elem1.link); - assert(elem1.link.next == &list2 && elem1.link.prev == &list2); + test_assert(linked_list_empty(&list1)); + test_assert(list2.next == &elem1.link && list2.prev == &elem1.link); + test_assert(elem1.link.next == &list2 && elem1.link.prev == &list2); } static void test_linked_list_take_many(void) { @@ -239,10 +239,10 @@ static void test_linked_list_take_many(void) { linked_list_take(&list2, &list1); - assert(linked_list_empty(&list1)); - assert(list2.next == &elem1.link && list2.prev == &elem2.link); - assert(elem1.link.next == &elem2.link && elem1.link.prev == &list2); - assert(elem2.link.next == &list2 && elem2.link.prev == &elem1.link); + test_assert(linked_list_empty(&list1)); + test_assert(list2.next == &elem1.link && list2.prev == &elem2.link); + test_assert(elem1.link.next == &elem2.link && elem1.link.prev == &list2); + test_assert(elem2.link.next == &list2 && elem2.link.prev == &elem1.link); } static void test_linked_list_take_concat(void) { @@ -261,31 +261,31 @@ static void test_linked_list_take_concat(void) { linked_list_take(&list2, &list1); - assert(linked_list_empty(&list1)); - assert(list2.next == &elem1.link && list2.prev == &elem4.link); - assert(elem1.link.next == &elem2.link && elem1.link.prev == &list2); - assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); - assert(elem3.link.next == &elem4.link && elem3.link.prev == &elem2.link); - assert(elem4.link.next == &list2 && elem4.link.prev == &elem3.link); + test_assert(linked_list_empty(&list1)); + test_assert(list2.next == &elem1.link && list2.prev == &elem4.link); + test_assert(elem1.link.next == &elem2.link && elem1.link.prev == &list2); + test_assert(elem2.link.next == &elem3.link && elem2.link.prev == &elem1.link); + test_assert(elem3.link.next == &elem4.link && elem3.link.prev == &elem2.link); + test_assert(elem4.link.next == &list2 && elem4.link.prev == &elem3.link); } int main(int argc, char *argv[]) { (void)argc; (void)argv; - test_linked_list_init(); - test_linked_list_single_insert(); - test_linked_list_single_remove(); - test_linked_list_alternate_remove(); - test_linked_list_sequential_remove(); - test_linked_list_insert_after(); - test_linked_list_remove_loop(); - test_linked_list_manual_iterate(); - test_linked_list_loop_iterate(); - test_linked_list_take_empty(); - test_linked_list_take_single(); - test_linked_list_take_many(); - test_linked_list_take_concat(); + test_run(test_linked_list_init); + test_run(test_linked_list_single_insert); + test_run(test_linked_list_single_remove); + test_run(test_linked_list_alternate_remove); + test_run(test_linked_list_sequential_remove); + test_run(test_linked_list_insert_after); + test_run(test_linked_list_remove_loop); + test_run(test_linked_list_manual_iterate); + test_run(test_linked_list_loop_iterate); + test_run(test_linked_list_take_empty); + test_run(test_linked_list_take_single); + test_run(test_linked_list_take_many); + test_run(test_linked_list_take_concat); return 0; } From 704d1ccd0b9e0da1f3555a07ba9184927983f812 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 22:00:15 +0200 Subject: [PATCH 018/211] server: Remember to remove seat from list --- seatd/server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/seatd/server.c b/seatd/server.c index 4562a71..9a71d66 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -53,6 +53,7 @@ void server_finish(struct server *server) { assert(server); while (!linked_list_empty(&server->seats)) { struct seat *seat = (struct seat *)server->seats.next; + linked_list_remove(&seat->link); seat_destroy(seat); } poller_finish(&server->poller); From c9ce7c71aa80769033b556d1c486da81c2fda551 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 22:08:59 +0200 Subject: [PATCH 019/211] poller: Remember to remove sources from list --- seatd/poller.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/seatd/poller.c b/seatd/poller.c index 74d5d89..53831e4 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -55,6 +55,7 @@ void poller_init(struct poller *poller) { int poller_finish(struct poller *poller) { while (!linked_list_empty(&poller->fds)) { struct event_source_fd *bpfd = (struct event_source_fd *)poller->fds.next; + linked_list_remove(&bpfd->link); free(bpfd); } while (!linked_list_empty(&poller->signals)) { @@ -66,6 +67,7 @@ int poller_finish(struct poller *poller) { sa.sa_flags = 0; sigaction(bps->signal, &sa, NULL); + linked_list_remove(&bps->link); free(bps); } free(poller->pollfds); From 5b8117f3d4ad767e5ddb8e202c938bc2e0174ffb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 31 Aug 2020 22:44:02 +0200 Subject: [PATCH 020/211] client: Do not leak idle clients on exit --- include/server.h | 1 + libseat/backend/seatd.c | 2 +- seatd/client.c | 2 ++ seatd/server.c | 7 +++++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/server.h b/include/server.h index 587047e..488915c 100644 --- a/include/server.h +++ b/include/server.h @@ -13,6 +13,7 @@ struct server { struct poller poller; struct linked_list seats; + struct linked_list idle_clients; }; int server_init(struct server *server); diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 400b357..fd424b5 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -599,7 +599,7 @@ static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, if (poller_poll(&server.poller) == -1) { log_errorf("Could not poll server socket: %s", strerror(errno)); res = 1; - goto server_error; + break; } } server_error: diff --git a/seatd/client.c b/seatd/client.c index d658454..bd46a86 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -138,6 +138,7 @@ static int handle_open_seat(struct client *client) { return -1; } + linked_list_remove(&client->link); if (seat_add_client(seat, client) == -1) { log_errorf("unable to add client to target seat: %s", strerror(errno)); return -1; @@ -174,6 +175,7 @@ static int handle_close_seat(struct client *client) { log_error("unable to remove client from seat"); return -1; } + linked_list_insert(&client->server->idle_clients, &client->link); struct proto_header header = { .opcode = SERVER_SEAT_CLOSED, diff --git a/seatd/server.c b/seatd/server.c index 9a71d66..1da8041 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -26,6 +26,7 @@ int server_init(struct server *server) { poller_init(&server->poller); linked_list_init(&server->seats); + linked_list_init(&server->idle_clients); if (poller_add_signal(&server->poller, SIGUSR1, server_handle_vt_rel, server) == NULL || poller_add_signal(&server->poller, SIGUSR2, server_handle_vt_acq, server) == NULL || @@ -51,6 +52,11 @@ int server_init(struct server *server) { void server_finish(struct server *server) { assert(server); + while (!linked_list_empty(&server->idle_clients)) { + struct client *client = (struct client *)server->idle_clients.next; + linked_list_remove(&client->link); + client_destroy(client); + } while (!linked_list_empty(&server->seats)) { struct seat *seat = (struct seat *)server->seats.next; linked_list_remove(&seat->link); @@ -131,6 +137,7 @@ int server_add_client(struct server *server, int fd) { } log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, client->gid); + linked_list_insert(&server->idle_clients, &client->link); return 0; } From 5d4036e9bd7891bc7f0906ac1f50d513f9e3a4de Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 1 Sep 2020 00:33:20 +0200 Subject: [PATCH 021/211] Move list removal to seat/client destroy --- seatd/client.c | 1 + seatd/seat.c | 1 + seatd/server.c | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/seatd/client.c b/seatd/client.c index bd46a86..8562c8b 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -89,6 +89,7 @@ void client_destroy(struct client *client) { } connection_close_fds(&client->connection); assert(linked_list_empty(&client->devices)); + linked_list_remove(&client->link); free(client); } diff --git a/seatd/seat.c b/seatd/seat.c index fee727c..7d62173 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -44,6 +44,7 @@ void seat_destroy(struct seat *seat) { } assert(seat->curttyfd == -1); + linked_list_remove(&seat->link); free(seat->seat_name); free(seat); } diff --git a/seatd/server.c b/seatd/server.c index 1da8041..c31fbba 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -54,12 +54,10 @@ void server_finish(struct server *server) { assert(server); while (!linked_list_empty(&server->idle_clients)) { struct client *client = (struct client *)server->idle_clients.next; - linked_list_remove(&client->link); client_destroy(client); } while (!linked_list_empty(&server->seats)) { struct seat *seat = (struct seat *)server->seats.next; - linked_list_remove(&seat->link); seat_destroy(seat); } poller_finish(&server->poller); From d53b3a87ec853bf04d745d731e6bc2136da4b13d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 1 Sep 2020 02:26:53 +0200 Subject: [PATCH 022/211] ci: ASan all build steps on arch --- .builds/archlinux.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 4d8cf63..419254f 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -10,7 +10,7 @@ sources: tasks: - prepare: | cd seatd - meson -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build + meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build - build: | cd seatd ninja -C build @@ -23,9 +23,6 @@ tasks: [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | cd seatd - rm -rf build - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build - ninja -C build timeout -s KILL 30s ./.builds/smoketest-seatd.sh - smoketest-builtin: | cd seatd From 34d0c87ea80d06bc55ea9d28fe2f4ce0d7d816c6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 1 Sep 2020 02:27:05 +0200 Subject: [PATCH 023/211] ci: ASan smoketest on FreeBSD --- .builds/freebsd.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 048f95c..ca9a3c1 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -6,7 +6,7 @@ sources: tasks: - prepare: | cd seatd - meson build -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build - build: | cd seatd ninja -C build @@ -15,6 +15,9 @@ tasks: ninja -C build test - smoketest: | cd seatd + rm -rf build + meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build + ninja -C build timeout -s KILL 30s ./.builds/smoketest-seatd.sh - smoketest-builtin: | cd seatd From ad214dc3fe6fbbf6e32532015ca54a484c5841b4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 1 Sep 2020 02:47:03 +0200 Subject: [PATCH 024/211] client: Only unlink if on the idle list --- seatd/client.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/seatd/client.c b/seatd/client.c index 8562c8b..bf339d9 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -80,8 +80,13 @@ void client_destroy(struct client *client) { client->connection.fd = -1; } if (client->seat != NULL) { - // This should also close and remove all devices + // This should also close and remove all devices. This unlinks + // the client. seat_remove_client(client); + } else { + // If we are not a member of a seat, we will be on the idle + // clients list, so unlink the client manually. + linked_list_remove(&client->link); } if (client->event_source != NULL) { event_source_fd_destroy(client->event_source); @@ -89,7 +94,6 @@ void client_destroy(struct client *client) { } connection_close_fds(&client->connection); assert(linked_list_empty(&client->devices)); - linked_list_remove(&client->link); free(client); } From 1867f29d4274fec57876246f206bac620cf23828 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 31 Aug 2020 20:08:12 +0200 Subject: [PATCH 025/211] meson: fix manpage generation for cross builds We want to use the scdoc of the host system not the target system, so pass the `native: true` parameter to meson. --- meson.build | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index bc167e8..cf2b445 100644 --- a/meson.build +++ b/meson.build @@ -180,10 +180,11 @@ test( ) ) -scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7') +scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) if scdoc.found() - sh = find_program('sh') + sh = find_program('sh', native: true) + scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) man_pages = ['seatd.1.scd'] @@ -199,7 +200,7 @@ if scdoc.found() input: 'man/' + src, output: output, command: [ - sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc.get_pkgconfig_variable('scdoc'), output) + sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) From 047d8b284c285ad4b5a643511adb1d0ba8a4e63e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 7 Sep 2020 23:33:50 +0200 Subject: [PATCH 026/211] libseat: Handle SERVER_ERROR correctly The connection buffer position was erroneously rewinded before reading the protocol message when the message was a SERVER_ERROR. --- libseat/backend/seatd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index fd424b5..0b8064d 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -165,14 +165,13 @@ static size_t read_header(struct backend_seatd *backend, uint16_t expected_opcod return SIZE_MAX; } if (header.opcode != expected_opcode) { - connection_restore(&backend->connection, sizeof header); struct proto_server_error msg; if (header.opcode != SERVER_ERROR) { log_errorf("Unexpected response: expected opcode %d, received opcode %d", expected_opcode, header.opcode); set_error(backend); errno = EBADMSG; - } else if (conn_get(backend, &msg, sizeof msg) == -1) { + } else if (header.size != sizeof msg || conn_get(backend, &msg, sizeof msg) == -1) { set_error(backend); errno = EBADMSG; } else { From 88136714862fe48c6e919ebc97c85b679cd2f92a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 7 Sep 2020 23:54:38 +0200 Subject: [PATCH 027/211] man: Mention assistance from other contributors --- man/seatd.1.scd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index c18910d..ab79ee1 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -51,5 +51,6 @@ The libseat library, ** # AUTHORS -Maintained by Kenny Levinsen . For more information about seatd -development, see https://sr.ht/~kennylevinsen/seatd. +Maintained by Kenny Levinsen , who is assisted by other +open-source contributors. For more information about seatd development, see +https://sr.ht/~kennylevinsen/seatd. From d4b1f4d44928ffbdd3221524af6fbd5f426edb8a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 8 Sep 2020 00:00:48 +0200 Subject: [PATCH 028/211] libseat: Version the .so file --- meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/meson.build b/meson.build index cf2b445..389de13 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,9 @@ project( ], ) +# Bump whenever ABI-breaking changes occur. +libseat_soversion = 1 + add_project_arguments( [ '-Wundef', @@ -135,6 +138,7 @@ 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' ], + soversion: libseat_soversion, link_with: private_lib, include_directories: [include_directories('.', 'include')], install: true, From fb5743971c731794758acd44bb08975b3ef15f2e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 8 Sep 2020 00:03:59 +0200 Subject: [PATCH 029/211] Bump version to 0.3.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 389de13..33eaa98 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.2.0', + version: '0.3.0', license: 'MIT', meson_version: '>=0.53.0', default_options: [ From 6747c5f3f8d677bd553699710c1b99f5ae98f309 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 18 Sep 2020 15:06:29 +0200 Subject: [PATCH 030/211] poller: Raise signals through self-pipe Signal handling relied on poll(2) being interrupted by signals, followed by a check for signal handlers flagging a signal as received. This only allowed signals that were received during poll(2) to be handled correctly. Implement the usual self-pipe implementation, where signal handlers write an arbitrary byte to a polled file descriptor to ensure proper level-triggered signal handling. --- include/poller.h | 5 +- seatd/poller.c | 251 +++++++++++++++++++++++++++-------------------- seatd/server.c | 5 +- 3 files changed, 151 insertions(+), 110 deletions(-) diff --git a/include/poller.h b/include/poller.h index f30bbda..63733e2 100644 --- a/include/poller.h +++ b/include/poller.h @@ -71,10 +71,11 @@ struct poller { struct linked_list signals; struct linked_list fds; + int signal_fds[2]; struct pollfd *pollfds; size_t pollfds_len; size_t fd_event_sources; - bool pollfds_dirty; + bool dirty; }; /** @@ -96,7 +97,7 @@ struct poll_impl { * Initializes the poller. The poller must be torn down with poller_finish when * it is no longer needed. */ -void poller_init(struct poller *poller); +int poller_init(struct poller *poller); /** * De-initializes the poller. This destroys all remaining event sources and diff --git a/seatd/poller.c b/seatd/poller.c index 53831e4..1d1b9b4 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -41,15 +42,54 @@ struct event_source_signal { /* Used for signal handling */ struct poller *global_poller = NULL; -void poller_init(struct poller *poller) { +static void signal_handler(int sig) { + if (global_poller == NULL) { + return; + } + for (struct linked_list *elem = global_poller->signals.next; + elem != &global_poller->signals; elem = elem->next) { + struct event_source_signal *bps = (struct event_source_signal *)elem; + if (bps->signal == sig) { + bps->raised = true; + } + } + int saved_errno = errno; + if (write(global_poller->signal_fds[1], "\0", 1) == -1 && errno != EAGAIN) { + // This is unfortunate. + } + errno = saved_errno; +} + +static int set_nonblock(int fd) { + int flags; + if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + return -1; + } + return 0; +} + +int poller_init(struct poller *poller) { assert(global_poller == NULL); + if (pipe(poller->signal_fds) == -1) { + return -1; + } + if (set_nonblock(poller->signal_fds[0]) == -1) { + return -1; + } + if (set_nonblock(poller->signal_fds[1]) == -1) { + return -1; + } + linked_list_init(&poller->fds); linked_list_init(&poller->signals); poller->pollfds = NULL; poller->pollfds_len = 0; - poller->fd_event_sources = 0; + poller->dirty = true; + poller->fd_event_sources = 1; global_poller = poller; + + return 0; } int poller_finish(struct poller *poller) { @@ -74,63 +114,6 @@ int poller_finish(struct poller *poller) { return 0; } -static int event_mask_to_poll_mask(uint32_t event_mask) { - int poll_mask = 0; - if (event_mask & EVENT_READABLE) { - poll_mask |= POLLIN; - } - if (event_mask & EVENT_WRITABLE) { - poll_mask |= POLLOUT; - } - return poll_mask; -} - -static uint32_t poll_mask_to_event_mask(int poll_mask) { - uint32_t event_mask = 0; - if (poll_mask & POLLIN) { - event_mask |= EVENT_READABLE; - } - if (poll_mask & POLLOUT) { - event_mask |= EVENT_WRITABLE; - } - if (poll_mask & POLLERR) { - event_mask |= EVENT_ERROR; - } - if (poll_mask & POLLHUP) { - event_mask |= EVENT_HANGUP; - } - return event_mask; -} - -static int regenerate_pollfds(struct poller *poller) { - if (!poller->pollfds_dirty) { - return 0; - } - - if (poller->fd_event_sources > poller->pollfds_len) { - struct pollfd *fds = calloc(poller->fd_event_sources, sizeof(struct pollfd)); - if (fds == NULL) { - return -1; - } - free(poller->pollfds); - poller->pollfds = fds; - poller->pollfds_len = poller->fd_event_sources; - } - - ssize_t idx = 0; - for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { - struct event_source_fd *bpfd = (struct event_source_fd *)elem; - bpfd->pollfd_idx = idx++; - poller->pollfds[bpfd->pollfd_idx] = (struct pollfd){ - .fd = bpfd->fd, - .events = event_mask_to_poll_mask(bpfd->mask), - }; - } - - poller->pollfds_dirty = false; - return 0; -} - struct event_source_fd *poller_add_fd(struct poller *poller, int fd, uint32_t mask, event_source_fd_func_t func, void *data) { struct event_source_fd *bpfd = calloc(1, sizeof(struct event_source_fd)); @@ -144,7 +127,7 @@ struct event_source_fd *poller_add_fd(struct poller *poller, int fd, uint32_t ma bpfd->poller = poller; bpfd->pollfd_idx = -1; poller->fd_event_sources += 1; - poller->pollfds_dirty = true; + poller->dirty = true; linked_list_insert(&poller->fds, &bpfd->link); return (struct event_source_fd *)bpfd; } @@ -153,7 +136,7 @@ int event_source_fd_destroy(struct event_source_fd *event_source) { struct event_source_fd *bpfd = (struct event_source_fd *)event_source; struct poller *poller = bpfd->poller; poller->fd_event_sources -= 1; - poller->pollfds_dirty = true; + poller->dirty = true; bpfd->killed = true; return 0; } @@ -162,23 +145,10 @@ int event_source_fd_update(struct event_source_fd *event_source, uint32_t mask) struct event_source_fd *bpfd = (struct event_source_fd *)event_source; struct poller *poller = bpfd->poller; event_source->mask = mask; - poller->pollfds_dirty = true; + poller->dirty = true; return 0; } -static void signal_handler(int sig) { - if (global_poller == NULL) { - return; - } - for (struct linked_list *elem = global_poller->signals.next; - elem != &global_poller->signals; elem = elem->next) { - struct event_source_signal *bps = (struct event_source_signal *)elem; - if (bps->signal == sig) { - bps->raised = true; - } - } -} - struct event_source_signal *poller_add_signal(struct poller *poller, int signal, event_source_signal_func_t func, void *data) { @@ -224,17 +194,101 @@ int event_source_signal_destroy(struct event_source_signal *event_source) { sigaction(bps->signal, &sa, NULL); } + poller->dirty = true; bps->killed = true; return 0; } -int poller_poll(struct poller *poller) { - if (regenerate_pollfds(poller) == -1) { - return -1; +static int event_mask_to_poll_mask(uint32_t event_mask) { + int poll_mask = 0; + if (event_mask & EVENT_READABLE) { + poll_mask |= POLLIN; + } + if (event_mask & EVENT_WRITABLE) { + poll_mask |= POLLOUT; + } + return poll_mask; +} + +static uint32_t poll_mask_to_event_mask(int poll_mask) { + uint32_t event_mask = 0; + if (poll_mask & POLLIN) { + event_mask |= EVENT_READABLE; + } + if (poll_mask & POLLOUT) { + event_mask |= EVENT_WRITABLE; + } + if (poll_mask & POLLERR) { + event_mask |= EVENT_ERROR; + } + if (poll_mask & POLLHUP) { + event_mask |= EVENT_HANGUP; + } + return event_mask; +} + +static int regenerate(struct poller *poller) { + if (poller->fd_event_sources > poller->pollfds_len) { + struct pollfd *fds = + realloc(poller->pollfds, poller->fd_event_sources * sizeof(struct pollfd)); + if (fds == NULL) { + return -1; + } + poller->pollfds = fds; + poller->pollfds_len = poller->fd_event_sources; } - if (poll(poller->pollfds, poller->fd_event_sources, -1) == -1 && errno != EINTR) { - return -1; + size_t idx = 0; + poller->pollfds[idx++] = (struct pollfd){ + .fd = poller->signal_fds[0], + .events = POLLIN, + }; + + for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { + struct event_source_fd *bpfd = (struct event_source_fd *)elem; + if (bpfd->killed) { + elem = elem->prev; + linked_list_remove(&bpfd->link); + free(bpfd); + } else { + bpfd->pollfd_idx = idx++; + assert(bpfd->pollfd_idx < (ssize_t)poller->pollfds_len); + poller->pollfds[bpfd->pollfd_idx] = (struct pollfd){ + .fd = bpfd->fd, + .events = event_mask_to_poll_mask(bpfd->mask), + }; + } + } + assert(idx == poller->fd_event_sources); + + for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; + elem = elem->next) { + struct event_source_signal *bps = (struct event_source_signal *)elem; + if (bps->killed) { + elem = elem->prev; + linked_list_remove(&bps->link); + free(bps); + } + } + + return 0; +} + +static void dispatch(struct poller *poller) { + if ((poller->pollfds[0].revents & POLLIN) != 0) { + char garbage[8]; + while (read(poller->signal_fds[0], &garbage, sizeof garbage) != -1) { + } + + for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; + elem = elem->next) { + struct event_source_signal *bps = (struct event_source_signal *)elem; + if (!bps->raised || bps->killed) { + continue; + } + bps->func(bps->signal, bps->data); + bps->raised = false; + } } for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { @@ -242,6 +296,7 @@ int poller_poll(struct poller *poller) { if (bpfd->pollfd_idx == -1 || bpfd->killed) { continue; } + assert(bpfd->pollfd_idx < (ssize_t)poller->pollfds_len); short revents = poller->pollfds[bpfd->pollfd_idx].revents; if (revents == 0) { continue; @@ -249,39 +304,21 @@ int poller_poll(struct poller *poller) { bpfd->func(poller->pollfds[bpfd->pollfd_idx].fd, poll_mask_to_event_mask(revents), bpfd->data); } +} - for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; - elem = elem->next) { - struct event_source_signal *bps = (struct event_source_signal *)elem; - if (!bps->raised || bps->killed) { - continue; +int poller_poll(struct poller *poller) { + if (poller->dirty) { + if (regenerate(poller) == -1) { + return -1; } - bps->func(bps->signal, bps->data); - bps->raised = false; + poller->dirty = false; } - for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { - struct event_source_fd *bpfd = (struct event_source_fd *)elem; - if (!bpfd->killed) { - continue; - } - - elem = elem->prev; - linked_list_remove(&bpfd->link); - free(bpfd); + if (poll(poller->pollfds, poller->fd_event_sources, -1) == -1 && errno != EINTR) { + return -1; } - for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; - elem = elem->next) { - struct event_source_signal *bps = (struct event_source_signal *)elem; - if (!bps->killed) { - continue; - } - - elem = elem->prev; - linked_list_remove(&bps->link); - free(bps); - } + dispatch(poller); return 0; } diff --git a/seatd/server.c b/seatd/server.c index c31fbba..5abe389 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -23,7 +23,10 @@ static int server_handle_vt_rel(int signal, void *data); static int server_handle_kill(int signal, void *data); int server_init(struct server *server) { - poller_init(&server->poller); + if (poller_init(&server->poller) == -1) { + log_errorf("could not initialize poller: %s", strerror(errno)); + return -1; + } linked_list_init(&server->seats); linked_list_init(&server->idle_clients); From d16122e98a1630d3ea96ff80dc3ea262660fd502 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 18 Sep 2020 15:13:09 +0200 Subject: [PATCH 031/211] client: Remove unnecessary active_client check --- seatd/client.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/seatd/client.c b/seatd/client.c index bf339d9..31a3fd5 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -295,13 +295,6 @@ static int handle_disable_seat(struct client *client) { return -1; } - struct seat *seat = client->seat; - if (seat->active_client != client) { - log_info("client is not currently active"); - errno = EPERM; - goto error; - } - if (seat_ack_disable_client(client) == -1) { goto error; } From 51c7467516d6213d1ff614e4db1e216de6367cc8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 18 Sep 2020 15:38:53 +0200 Subject: [PATCH 032/211] seat: Rework seat activation/switch logic The seat activation logic did not correctly handle VT switching and switching between multiple sessions. Session switching on VT-bound seats is now performed using a VT switch, taking advantage of VT signals to perform the actual switch. This simplifies switching logic and makes it more robust. --- include/client.h | 3 +- include/seat.h | 8 +- seatd/client.c | 13 +- seatd/seat.c | 350 ++++++++++++++++++++++++----------------------- seatd/server.c | 2 +- 5 files changed, 186 insertions(+), 190 deletions(-) diff --git a/include/client.h b/include/client.h index 75e4f46..3b1f105 100644 --- a/include/client.h +++ b/include/client.h @@ -21,7 +21,7 @@ struct client { gid_t gid; struct seat *seat; - int seat_vt; + int session; bool pending_disable; struct linked_list devices; @@ -31,7 +31,6 @@ struct client *client_create(struct server *server, int client_fd); void client_destroy(struct client *client); int client_handle_connection(int fd, uint32_t mask, void *data); -int client_get_session(const struct client *client); int client_send_enable_seat(struct client *client); int client_send_disable_seat(struct client *client); diff --git a/include/seat.h b/include/seat.h index 30f7cc4..2d269cc 100644 --- a/include/seat.h +++ b/include/seat.h @@ -33,9 +33,9 @@ struct seat { struct client *next_client; bool vt_bound; - bool vt_pending_ack; - int next_vt; - int curttyfd; + int cur_ttyfd; + int cur_vt; + int session_cnt; }; struct seat *seat_create(const char *name, bool vt_bound); @@ -52,7 +52,7 @@ int seat_close_device(struct client *client, struct seat_device *seat_device); struct seat_device *seat_find_device(struct client *client, int device_id); int seat_set_next_session(struct client *client, int session); -int seat_activate(struct seat *seat); +int seat_vt_activate(struct seat *seat); int seat_prepare_vt_switch(struct seat *seat); #endif diff --git a/seatd/client.c b/seatd/client.c index 31a3fd5..fcb238d 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -66,6 +66,7 @@ struct client *client_create(struct server *server, int client_fd) { client->uid = uid; client->gid = gid; client->pid = pid; + client->session = -1; client->server = server; client->connection.fd = client_fd; linked_list_init(&client->devices); @@ -453,15 +454,3 @@ fail: client_destroy(client); return -1; } - -int client_get_session(const struct client *client) { - if (client->seat == NULL || client->seat->active_client != client) { - return -1; - } - if (client->seat->vt_bound) { - return client->seat_vt; - } - // TODO: Store some session sequence - errno = ENOSYS; - return -1; -} diff --git a/seatd/seat.c b/seatd/seat.c index 7d62173..f95cbf7 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -25,8 +25,9 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { } linked_list_init(&seat->clients); seat->vt_bound = vt_bound; - seat->curttyfd = -1; seat->seat_name = strdup(seat_name); + seat->cur_vt = 0; + seat->cur_ttyfd = -1; if (seat->seat_name == NULL) { free(seat); return NULL; @@ -42,13 +43,73 @@ void seat_destroy(struct seat *seat) { assert(client->seat == seat); client_destroy(client); } - assert(seat->curttyfd == -1); - + assert(seat->cur_ttyfd == -1); linked_list_remove(&seat->link); free(seat->seat_name); free(seat); } +static void seat_update_vt(struct seat *seat) { + int tty0fd = terminal_open(0); + if (tty0fd == -1) { + log_errorf("unable to open tty0: %s", strerror(errno)); + return; + } + seat->cur_vt = terminal_current_vt(tty0fd); + close(tty0fd); +} + +static int vt_open(struct seat *seat, int vt) { + assert(vt != -1); + assert(seat->cur_ttyfd == -1); + seat->cur_ttyfd = terminal_open(vt); + if (seat->cur_ttyfd == -1) { + log_errorf("could not open terminal for vt %d: %s", vt, strerror(errno)); + return -1; + } + + terminal_set_process_switching(seat->cur_ttyfd, true); + terminal_set_keyboard(seat->cur_ttyfd, false); + terminal_set_graphics(seat->cur_ttyfd, true); + return 0; +} + +static void vt_close(struct seat *seat) { + if (seat->cur_ttyfd == -1) { + return; + } + + terminal_set_process_switching(seat->cur_ttyfd, true); + terminal_set_keyboard(seat->cur_ttyfd, true); + terminal_set_graphics(seat->cur_ttyfd, false); + + close(seat->cur_ttyfd); + seat->cur_ttyfd = -1; +} + +static int vt_switch(int vt) { + int ttyfd = terminal_open(0); + if (ttyfd == -1) { + log_errorf("could not open terminal: %s", strerror(errno)); + return -1; + } + terminal_set_process_switching(ttyfd, true); + terminal_switch_vt(ttyfd, vt); + close(ttyfd); + return 0; +} + +static int vt_ack(void) { + int tty0fd = terminal_open(0); + if (tty0fd == -1) { + log_errorf("unable to open tty0: %s", strerror(errno)); + return -1; + } + terminal_ack_switch(tty0fd); + close(tty0fd); + return 0; +} + int seat_add_client(struct seat *seat, struct client *client) { assert(seat); assert(client); @@ -63,6 +124,23 @@ int seat_add_client(struct seat *seat, struct client *client) { return -1; } + if (client->session != -1) { + log_error("cannot add client: client cannot be reused"); + return -1; + } + + if (seat->vt_bound) { + seat_update_vt(seat); + if (seat->cur_vt == -1) { + log_error("could not determine VT for client"); + return -1; + } + client->session = seat->cur_vt; + } else { + client->session = seat->session_cnt++; + } + log_debugf("registered client %p as session %d", (void *)client, client->session); + client->seat = seat; linked_list_insert(&seat->clients, &client->link); @@ -316,24 +394,47 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ return 0; } +static int seat_activate(struct seat *seat) { + assert(seat); + + if (seat->active_client != NULL) { + return 0; + } + + struct client *next_client = NULL; + if (seat->next_client != NULL) { + log_info("activating next queued client"); + next_client = seat->next_client; + seat->next_client = NULL; + } else if (linked_list_empty(&seat->clients)) { + log_info("no clients on seat to activate"); + return -1; + } else if (seat->vt_bound) { + for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; + elem = elem->next) { + struct client *client = (struct client *)elem; + if (client->session == seat->cur_vt) { + log_infof("activating client belonging to VT %d", seat->cur_vt); + next_client = client; + goto done; + } + } + + log_infof("no clients belonging to VT %d to activate", seat->cur_vt); + return -1; + } else { + log_info("activating first client on seat"); + next_client = (struct client *)seat->clients.next; + } + +done: + return seat_open_client(seat, next_client); +} + int seat_open_client(struct seat *seat, struct client *client) { assert(seat); assert(client); - - if (seat->vt_bound && client->seat_vt == 0) { - int tty0fd = terminal_open(0); - if (tty0fd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); - return -1; - } - client->seat_vt = terminal_current_vt(tty0fd); - close(tty0fd); - if (client->seat_vt == -1) { - log_errorf("unable to get current VT for client: %s", strerror(errno)); - client->seat_vt = 0; - return -1; - } - } + assert(!client->pending_disable); if (seat->active_client != NULL) { log_error("client already active"); @@ -341,19 +442,8 @@ int seat_open_client(struct seat *seat, struct client *client) { return -1; } - assert(seat->curttyfd == -1); - - if (seat->vt_bound) { - int ttyfd = terminal_open(client->seat_vt); - if (ttyfd == -1) { - log_errorf("unable to open tty for vt %d: %s", client->seat_vt, - strerror(errno)); - return -1; - } - terminal_set_process_switching(ttyfd, true); - terminal_set_keyboard(ttyfd, false); - terminal_set_graphics(ttyfd, true); - seat->curttyfd = ttyfd; + if (seat->vt_bound && vt_open(seat, client->session) == -1) { + return -1; } for (struct linked_list *elem = client->devices.next; elem != &client->devices; @@ -395,8 +485,13 @@ int seat_close_client(struct client *client) { client->pending_disable = false; seat->active_client = NULL; - seat_activate(seat); log_debug("closed client"); + + if (seat->vt_bound) { + vt_close(seat); + } + + seat_activate(seat); return 0; } @@ -412,6 +507,12 @@ static int seat_disable_client(struct client *client) { return -1; } + if (client->pending_disable) { + log_error("client already pending disable"); + errno = EBUSY; + return -1; + } + // We *deactivate* all remaining fds. These may later be reactivated. // The reason we cannot just close them is that certain device fds, such // as for DRM, must maintain the exact same file description for their @@ -439,17 +540,23 @@ int seat_ack_disable_client(struct client *client) { assert(client->seat); struct seat *seat = client->seat; - - if (seat->active_client != client || !client->pending_disable) { - log_error("client not active or not pending disable"); + if (!client->pending_disable) { + log_error("client not pending disable"); errno = EBUSY; return -1; } client->pending_disable = false; - seat->active_client = NULL; - seat_activate(seat); log_debug("disabled client"); + + if (seat->active_client == client) { + if (seat->vt_bound) { + vt_close(seat); + } + + seat->active_client = NULL; + seat_activate(seat); + } return 0; } @@ -465,180 +572,81 @@ int seat_set_next_session(struct client *client, int session) { return -1; } - if (session == client_get_session(client)) { - log_info("requested session is already active"); - return 0; - } - - // Check if the session number is valid if (session <= 0) { log_errorf("invalid session value: %d", session); errno = EINVAL; return -1; } - // Check if a switch is already queued - if (seat->next_vt > 0 || seat->next_client != NULL) { + if (session == client->session) { + log_info("requested session is already active"); + return 0; + } + + if (seat->next_client != NULL) { log_info("switch is already queued"); return 0; } - struct client *target = NULL; + if (seat->vt_bound) { + log_infof("switching to VT %d from %d", session, seat->cur_vt); + if (vt_switch(session) == -1) { + log_error("could not switch VT"); + return -1; + } + return 0; + } + struct client *target = NULL; for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; elem = elem->next) { struct client *c = (struct client *)elem; - if (client_get_session(c) == session) { + if (c->session == session) { target = c; break; } } - if (target != NULL) { - log_info("queuing switch to different client"); - seat->next_client = target; - seat->next_vt = 0; - } else if (seat->vt_bound) { - log_info("queuing switch to different VT"); - seat->next_vt = session; - seat->next_client = NULL; - } else { + if (target == NULL) { log_error("no valid switch available"); errno = EINVAL; return -1; } + log_infof("queuing switch client with session %d", session); + seat->next_client = target; seat_disable_client(seat->active_client); return 0; } -int seat_activate(struct seat *seat) { +int seat_vt_activate(struct seat *seat) { assert(seat); - - // We already have an active client! - if (seat->active_client != NULL) { - return 0; - } - - int vt = -1; - if (seat->vt_bound) { - int ttyfd = terminal_open(0); - if (ttyfd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); - return -1; - } - - // If we need to ack a switch, do that - if (seat->vt_pending_ack) { - log_info("acking pending VT switch"); - seat->vt_pending_ack = false; - if (seat->curttyfd != -1) { - terminal_set_process_switching(seat->curttyfd, true); - terminal_set_keyboard(seat->curttyfd, true); - terminal_set_graphics(seat->curttyfd, false); - close(seat->curttyfd); - seat->curttyfd = -1; - } - return 0; - } - - // If we're asked to do a simple VT switch, do that - if (seat->next_vt > 0) { - log_info("executing VT switch"); - if (seat->curttyfd != -1) { - terminal_set_process_switching(seat->curttyfd, true); - terminal_set_keyboard(seat->curttyfd, true); - terminal_set_graphics(seat->curttyfd, false); - close(seat->curttyfd); - seat->curttyfd = -1; - } - terminal_switch_vt(ttyfd, seat->next_vt); - seat->next_vt = 0; - close(ttyfd); - return 0; - } - - // We'll need the VT below - vt = terminal_current_vt(ttyfd); - if (vt == -1) { - log_errorf("unable to get vt: %s", strerror(errno)); - close(ttyfd); - return -1; - } - close(ttyfd); - } - - // Try to pick a client for activation - struct client *next_client = NULL; - if (seat->next_client != NULL) { - // A specific client has been requested, use it - next_client = seat->next_client; - seat->next_client = NULL; - } else if (!linked_list_empty(&seat->clients) && seat->vt_bound) { - // No client is requested, try to find an applicable one - for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; - elem = elem->next) { - struct client *client = (struct client *)elem; - if (client->seat_vt == vt) { - next_client = client; - break; - } - } - } else if (!linked_list_empty(&seat->clients)) { - next_client = (struct client *)seat->clients.next; - } - - if (next_client == NULL) { - // No suitable client found - log_info("no client suitable for activation"); - if (seat->vt_bound && seat->curttyfd != -1) { - terminal_set_process_switching(seat->curttyfd, false); - terminal_set_keyboard(seat->curttyfd, true); - terminal_set_graphics(seat->curttyfd, false); - close(seat->curttyfd); - seat->curttyfd = -1; - } + if (!seat->vt_bound) { + log_debug("VT activation on non VT-bound seat, ignoring"); return -1; } - log_info("activating next client"); - if (seat->vt_bound && next_client->seat_vt != vt) { - int ttyfd = terminal_open(0); - if (ttyfd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); - return -1; - } - terminal_switch_vt(ttyfd, next_client->seat_vt); - close(ttyfd); + log_debug("switching session from VT activation"); + seat_update_vt(seat); + if (seat->active_client == NULL) { + seat_activate(seat); } - - return seat_open_client(seat, next_client); + return 0; } int seat_prepare_vt_switch(struct seat *seat) { assert(seat); - - if (seat->active_client == NULL) { - log_info("no active client, performing switch immediately"); - int tty0fd = terminal_open(0); - if (tty0fd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); - return -1; - } - terminal_ack_switch(tty0fd); - close(tty0fd); - return 0; + if (!seat->vt_bound) { + log_debug("VT switch request on non VT-bound seat, ignoring"); + return -1; } - if (seat->vt_pending_ack) { - log_info("impatient user, killing session to force pending switch"); - seat_close_client(seat->active_client); - return 0; + log_debug("acking VT switch"); + if (seat->active_client != NULL) { + seat_disable_client(seat->active_client); } - log_debug("delaying VT switch acknowledgement"); - - seat->vt_pending_ack = true; - seat_disable_client(seat->active_client); + vt_ack(); + seat->cur_vt = -1; return 0; } diff --git a/seatd/server.c b/seatd/server.c index 5abe389..90aa610 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -85,7 +85,7 @@ static int server_handle_vt_acq(int signal, void *data) { return -1; } - seat_activate(seat); + seat_vt_activate(seat); return 0; } From 8cb076d0a402f32db093f26a007d60fea1fefb15 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 19 Sep 2020 14:54:59 +0200 Subject: [PATCH 033/211] seat: Plug leak of deactivated fds Only if a device had an fd and was active would an fd be closed. As devices are deactivated early on session switch, this lead to fd leakage. Close fds regardless of active state. --- seatd/seat.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index f95cbf7..9f3d882 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -309,30 +309,29 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { seat_device->ref_cnt--; if (seat_device->ref_cnt > 0) { - // We still have more references to this device, so leave it be. return 0; } - // The ref count hit zero, so destroy the device linked_list_remove(&seat_device->link); - if (seat_device->active && seat_device->fd != -1) { - switch (seat_device->type) { - case SEAT_DEVICE_TYPE_DRM: - if (drm_drop_master(seat_device->fd) == -1) { - log_debugf("drm_drop_master failed: %s", strerror(errno)); + if (seat_device->fd != -1) { + if (seat_device->active) { + switch (seat_device->type) { + case SEAT_DEVICE_TYPE_DRM: + if (drm_drop_master(seat_device->fd) == -1) { + log_debugf("drm_drop_master failed: %s", strerror(errno)); + } + break; + case SEAT_DEVICE_TYPE_EVDEV: + if (evdev_revoke(seat_device->fd) == -1) { + log_debugf("evdev_revoke failed: %s", strerror(errno)); + } + break; + default: + log_error("invalid seat device type"); + abort(); } - break; - case SEAT_DEVICE_TYPE_EVDEV: - if (evdev_revoke(seat_device->fd) == -1) { - log_debugf("evdev_revoke failed: %s", strerror(errno)); - } - break; - default: - log_error("invalid seat device type"); - abort(); } close(seat_device->fd); - seat_device->fd = -1; } free(seat_device->path); free(seat_device); From 695a86aaa830ba759f77574c747487a8c79d78c8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 19 Sep 2020 19:16:29 +0200 Subject: [PATCH 034/211] seat: Reuse deactivate logic, more logging --- seatd/seat.c | 90 ++++++++++++++++++++++------------------------------ 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index 9f3d882..d11ca5a 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -227,20 +227,19 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { int device_id = 1; size_t device_count = 0; + struct seat_device *device = NULL; for (struct linked_list *elem = client->devices.next; elem != &client->devices; elem = elem->next) { - struct seat_device *device = (struct seat_device *)elem; + struct seat_device *old_device = (struct seat_device *)elem; - // If the device already exists, increase the ref count and - // return it. - if (strcmp(device->path, path) == 0) { - device->ref_cnt++; - return device; + if (strcmp(old_device->path, sanitized_path) == 0) { + old_device->ref_cnt++; + device = old_device; + goto done; } - // If the device has a higher id, up our device id - if (device->device_id >= device_id) { - device_id = device->device_id + 1; + if (old_device->device_id >= device_id) { + device_id = old_device->device_id + 1; } device_count++; } @@ -271,7 +270,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { abort(); } - struct seat_device *device = calloc(1, sizeof(struct seat_device)); + device = calloc(1, sizeof(struct seat_device)); if (device == NULL) { log_errorf("could not alloc device for '%s': %s", sanitized_path, strerror(errno)); close(fd); @@ -287,57 +286,20 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { return NULL; } - log_debugf("seat: %p, client: %p, path: '%s', device_id: %d", (void *)seat, (void *)client, - path, device_id); - device->ref_cnt = 1; device->type = type; device->fd = fd; device->device_id = device_id; device->active = true; linked_list_insert(&client->devices, &device->link); + +done: + log_debugf("seat: %p, client: %p, path: '%s', device_id: %d, ref_cnt: %d", (void *)seat, + (void *)client, path, device_id, device->ref_cnt); + return device; } -int seat_close_device(struct client *client, struct seat_device *seat_device) { - assert(client); - assert(client->seat); - assert(seat_device && seat_device->fd != -1); - - log_debugf("seat: %p, client: %p, path: '%s', device_id: %d", (void *)client->seat, - (void *)client, seat_device->path, seat_device->device_id); - - seat_device->ref_cnt--; - if (seat_device->ref_cnt > 0) { - return 0; - } - - linked_list_remove(&seat_device->link); - if (seat_device->fd != -1) { - if (seat_device->active) { - switch (seat_device->type) { - case SEAT_DEVICE_TYPE_DRM: - if (drm_drop_master(seat_device->fd) == -1) { - log_debugf("drm_drop_master failed: %s", strerror(errno)); - } - break; - case SEAT_DEVICE_TYPE_EVDEV: - if (evdev_revoke(seat_device->fd) == -1) { - log_debugf("evdev_revoke failed: %s", strerror(errno)); - } - break; - default: - log_error("invalid seat device type"); - abort(); - } - } - close(seat_device->fd); - } - free(seat_device->path); - free(seat_device); - return 0; -} - static int seat_deactivate_device(struct client *client, struct seat_device *seat_device) { assert(client); assert(client->seat); @@ -367,6 +329,30 @@ static int seat_deactivate_device(struct client *client, struct seat_device *sea return 0; } +int seat_close_device(struct client *client, struct seat_device *seat_device) { + assert(client); + assert(client->seat); + assert(seat_device && seat_device->fd != -1); + + log_debugf("seat: %p, client: %p, path: '%s', device_id: %d, ref_cnt: %d", + (void *)client->seat, (void *)client, seat_device->path, seat_device->device_id, + seat_device->ref_cnt); + + seat_device->ref_cnt--; + if (seat_device->ref_cnt > 0) { + return 0; + } + + linked_list_remove(&seat_device->link); + if (seat_device->fd != -1) { + seat_deactivate_device(client, seat_device); + close(seat_device->fd); + } + free(seat_device->path); + free(seat_device); + return 0; +} + static int seat_activate_device(struct client *client, struct seat_device *seat_device) { assert(client); assert(client->seat); From 9c6682a8311c3d05a11ffa365bd46a561da4289e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 19 Sep 2020 19:16:38 +0200 Subject: [PATCH 035/211] seatd: Log on exit --- seatd/seatd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/seatd/seatd.c b/seatd/seatd.c index ce4d2bb..bcd73b2 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -158,5 +158,6 @@ int main(int argc, char *argv[]) { server_finish(&server); unlink(socket_path); + log_info("seatd stopped"); return 0; } From 4c22c7b00414ad93809adc619062ca89345aeaa1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 19 Sep 2020 21:33:55 +0200 Subject: [PATCH 036/211] libseat: Dispatch all non-bg events on IPC call Dispatch on IPC call only dispatched until the first message was successfully processed. This could lead to premature dispatch termination if a background event was received during an IPC call. Instead, continue dispatching until a non-bg opcode is reported or an error is received. --- libseat/backend/seatd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 0b8064d..2f7b384 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -288,16 +288,20 @@ static int dispatch(struct backend_seatd *backend) { if (conn_flush(backend) == -1) { return -1; } - int opcode = 0, res = 0; - while ((res = dispatch_pending(backend, &opcode)) == 0 && opcode == 0) { + while (true) { + int opcode = 0; + if (dispatch_pending(backend, &opcode) == -1) { + log_errorf("Could not dispatch pending messages: %s", strerror(errno)); + return -1; + } + if (opcode != 0) { + break; + } if (poll_connection(backend, -1) == -1) { log_errorf("Could not poll connection: %s", strerror(errno)); return -1; } } - if (res == -1) { - return -1; - } return 0; } From 6fa82930d0c5660eea3102989c765dc864514e36 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 19 Sep 2020 21:58:09 +0200 Subject: [PATCH 037/211] libseat: Execute bg events after IPC calls If a background event was queued during call dispatch, and no unread data was left on the socket, there would be no incentive for the user to call dispatch, and as a result, the events would never be executed. Execute events at the end of IPC calls that read from the socket to avoid stalls. --- libseat/backend/seatd.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 2f7b384..b0e023f 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -379,6 +379,7 @@ static struct libseat *_open_seat(struct libseat_seat_listener *listener, void * goto backend_error; } + execute_events(backend); return &backend->base; backend_error: @@ -412,10 +413,12 @@ static int close_seat(struct libseat *base) { goto error; } + execute_events(backend); destroy(backend); return 0; error: + execute_events(backend); destroy(backend); return -1; } @@ -447,16 +450,21 @@ static int open_device(struct libseat *base, const char *path, int *fd) { if (conn_put(backend, &header, sizeof header) == -1 || conn_put(backend, &msg, sizeof msg) == -1 || conn_put(backend, path, pathlen) == -1 || dispatch(backend) == -1) { - return -1; + goto error; } struct proto_server_device_opened rmsg; if (read_header(backend, SERVER_DEVICE_OPENED, sizeof rmsg, false) == SIZE_MAX || conn_get(backend, &rmsg, sizeof rmsg) == -1 || conn_get_fd(backend, fd)) { - return -1; + goto error; } + execute_events(backend); return rmsg.device_id; + +error: + execute_events(backend); + return -1; } static int close_device(struct libseat *base, int device_id) { @@ -479,14 +487,19 @@ static int close_device(struct libseat *base, int device_id) { }; if (conn_put(backend, &header, sizeof header) == -1 || conn_put(backend, &msg, sizeof msg) == -1 || dispatch(backend) == -1) { - return -1; + goto error; } if (read_header(backend, SERVER_DEVICE_CLOSED, 0, false) == SIZE_MAX) { - return -1; + goto error; } + execute_events(backend); return 0; + +error: + execute_events(backend); + return -1; } static int switch_session(struct libseat *base, int session) { From 6da52fff236c612ffdb803a8d1ede40398c6d070 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 20 Sep 2020 03:14:09 +0200 Subject: [PATCH 038/211] poller: Add unittest --- meson.build | 8 +++ seatd/poller.c | 1 + tests/poller.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 tests/poller.c diff --git a/meson.build b/meson.build index 33eaa98..fa000c1 100644 --- a/meson.build +++ b/meson.build @@ -183,6 +183,14 @@ test( include_directories: [include_directories('.', 'include')], ) ) +test( + 'poller', + executable( + 'poller_test', + ['common/linked_list.c', 'seatd/poller.c', 'tests/poller.c'], + include_directories: [include_directories('.', 'include')], + ) +) scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) diff --git a/seatd/poller.c b/seatd/poller.c index 1d1b9b4..267929b 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -111,6 +111,7 @@ int poller_finish(struct poller *poller) { free(bps); } free(poller->pollfds); + global_poller = NULL; return 0; } diff --git a/tests/poller.c b/tests/poller.c new file mode 100644 index 0000000..382d9d2 --- /dev/null +++ b/tests/poller.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include + +#include "poller.h" +#include "test.h" + +static void test_poller_init(void) { + struct poller poller; + test_assert(poller_init(&poller) == 0); + poller_finish(&poller); +} + +struct test_fd { + int fd; + uint32_t events; +}; + +static int test_fd_event(int fd, uint32_t mask, void *data) { + struct test_fd *d = data; + d->fd = fd; + d->events = mask; + return 0; +} + +static void test_poller_single_fd(void) { + struct poller poller; + test_assert(poller_init(&poller) == 0); + + int fds[2]; + test_assert(pipe(fds) == 0); + + struct test_fd evd; + struct event_source_fd *ev = + poller_add_fd(&poller, fds[0], EVENT_READABLE, test_fd_event, &evd); + test_assert(ev != NULL); + + evd.fd = 0; + evd.events = 0; + test_assert(write(fds[1], "\0", 1) == 1); + test_assert(poller_poll(&poller) == 0); + test_assert(evd.fd == fds[0]); + test_assert(evd.events == EVENT_READABLE); + + evd.fd = 0; + evd.events = 0; + test_assert(write(fds[1], "\0", 1) == 1); + test_assert(poller_poll(&poller) == 0); + test_assert(evd.fd == fds[0]); + test_assert(evd.events == EVENT_READABLE); + + close(fds[0]); + close(fds[1]); + poller_finish(&poller); +} + +static void test_poller_multi_fd(void) { + struct poller poller; + test_assert(poller_init(&poller) == 0); + + char dummy[8]; + int fdsa[2], fdsb[2]; + test_assert(pipe(fdsa) == 0); + test_assert(pipe(fdsb) == 0); + + struct test_fd evd1, evd2; + struct event_source_fd *ev1 = + poller_add_fd(&poller, fdsa[0], EVENT_READABLE, test_fd_event, &evd1); + struct event_source_fd *ev2 = + poller_add_fd(&poller, fdsb[0], EVENT_READABLE, test_fd_event, &evd2); + test_assert(ev1 != NULL); + test_assert(ev2 != NULL); + + evd1.fd = evd2.fd = 0; + evd1.events = evd2.events = 0; + test_assert(write(fdsa[1], "\0", 1) == 1); + test_assert(poller_poll(&poller) == 0); + test_assert(read(fdsa[0], &dummy, sizeof dummy) == 1); + test_assert(evd1.fd == fdsa[0]); + test_assert(evd1.events == EVENT_READABLE); + test_assert(evd2.fd == 0); + test_assert(evd2.events == 0); + + evd1.fd = evd2.fd = 0; + evd1.events = evd2.events = 0; + test_assert(write(fdsb[1], "\0", 1) == 1); + test_assert(poller_poll(&poller) == 0); + test_assert(read(fdsb[0], &dummy, sizeof dummy) == 1); + test_assert(evd1.fd == 0); + test_assert(evd1.events == 0); + test_assert(evd2.fd == fdsb[0]); + test_assert(evd2.events == EVENT_READABLE); + + evd1.fd = evd2.fd = 0; + evd1.events = evd2.events = 0; + test_assert(write(fdsa[1], "\0", 1) == 1); + test_assert(write(fdsb[1], "\0", 1) == 1); + test_assert(poller_poll(&poller) == 0); + test_assert(read(fdsa[0], &dummy, sizeof dummy) == 1); + test_assert(read(fdsb[0], &dummy, sizeof dummy) == 1); + test_assert(evd1.fd == fdsa[0]); + test_assert(evd1.events == EVENT_READABLE); + test_assert(evd2.fd == fdsb[0]); + test_assert(evd2.events == EVENT_READABLE); + + close(fdsa[0]); + close(fdsa[1]); + close(fdsb[0]); + close(fdsb[1]); + poller_finish(&poller); +} + +struct test_signal { + int signal; +}; + +static int test_signal_event(int signal, void *data) { + struct test_signal *d = data; + d->signal = signal; + return 0; +} + +static void test_poller_single_signal(void) { + struct poller poller; + test_assert(poller_init(&poller) == 0); + + struct test_signal evd; + struct event_source_signal *ev = + poller_add_signal(&poller, SIGRTMIN, test_signal_event, &evd); + test_assert(ev != NULL); + + evd.signal = 0; + test_assert(kill(getpid(), SIGRTMIN) == 0); + test_assert(poller_poll(&poller) == 0); + test_assert(evd.signal == SIGRTMIN); + + evd.signal = 0; + test_assert(kill(getpid(), SIGRTMIN) == 0); + test_assert(poller_poll(&poller) == 0); + test_assert(evd.signal == SIGRTMIN); + + poller_finish(&poller); +} + +static void test_poller_multi_signal(void) { + struct poller poller; + test_assert(poller_init(&poller) == 0); + + struct test_signal evd1, evd2; + struct event_source_signal *ev1 = + poller_add_signal(&poller, SIGRTMIN, test_signal_event, &evd1); + struct event_source_signal *ev2 = + poller_add_signal(&poller, SIGRTMIN + 1, test_signal_event, &evd2); + test_assert(ev1 != NULL); + test_assert(ev2 != NULL); + + evd1.signal = evd2.signal = 0; + test_assert(kill(getpid(), SIGRTMIN) == 0); + test_assert(poller_poll(&poller) == 0); + test_assert(evd1.signal == SIGRTMIN); + test_assert(evd2.signal == 0); + + evd1.signal = evd2.signal = 0; + test_assert(kill(getpid(), SIGRTMIN + 1) == 0); + test_assert(poller_poll(&poller) == 0); + test_assert(evd1.signal == 0); + test_assert(evd2.signal == SIGRTMIN + 1); + + evd1.signal = evd2.signal = 0; + test_assert(kill(getpid(), SIGRTMIN) == 0); + test_assert(kill(getpid(), SIGRTMIN + 1) == 0); + test_assert(poller_poll(&poller) == 0); + test_assert(evd1.signal == SIGRTMIN); + test_assert(evd2.signal == SIGRTMIN + 1); + + poller_finish(&poller); +} + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + test_run(test_poller_init); + test_run(test_poller_single_fd); + test_run(test_poller_multi_fd); + test_run(test_poller_single_signal); + test_run(test_poller_multi_signal); +} From a763e16f26529323cd23a84a53f8d03431133d91 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 00:49:04 +0200 Subject: [PATCH 039/211] drm: Relax drm file detection, support FreeBSD Path check was done on /dev/dri/card and /dev/dri/renderD. However, /dev/dri/by-path is a thing, and on FreeBSD, /dev/dri/ symlinks to /dev/drm/. Relax Linux check to /dev/dri/, and add FreeBSD check for /dev/drm/. --- common/drm.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/common/drm.c b/common/drm.c index 8be2c62..897028c 100644 --- a/common/drm.c +++ b/common/drm.c @@ -24,24 +24,22 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -static int path_is_drm_card(const char *path) { - static const char prefix[] = "/dev/dri/card"; - static const int prefixlen = STRLEN(prefix); - return strncmp(prefix, path, prefixlen) == 0; -} - -static int path_is_drm_render(const char *path) { - static const char prefix[] = "/dev/dri/renderD"; - static const int prefixlen = STRLEN(prefix); - return strncmp(prefix, path, prefixlen) == 0; -} - -int path_is_drm(const char *path) { - return path_is_drm_card(path) || path_is_drm_render(path); -} - #if defined(__linux__) +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; } +#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; +} +#else +#error Unsupported platform #endif From 884c1416b302e9d855453d8e83cc09e54796a434 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 01:12:33 +0200 Subject: [PATCH 040/211] meson: Make default seatd socket path configurable FreeBSD and Linux have different preferred socket locations. Expose an option to set the location, and implement simple auto-logic for linux/freebsd. --- libseat/backend/seatd.c | 4 ++-- meson.build | 11 +++++++++++ meson_options.txt | 2 +- seatd/seatd.c | 6 +++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index b0e023f..1259308 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -67,9 +67,9 @@ static int seatd_connect(void) { close(fd); return -1; } - char *path = getenv("SEATD_SOCK"); + const char *path = getenv("SEATD_SOCK"); if (path == NULL) { - path = "/run/seatd.sock"; + path = SEATD_DEFAULTPATH; } addr.unix.sun_family = AF_UNIX; strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path); diff --git a/meson.build b/meson.build index fa000c1..1ab3d87 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,16 @@ project( # Bump whenever ABI-breaking changes occur. libseat_soversion = 1 +defaultpath = get_option('defaultpath') +if defaultpath == '' + system = target_machine.system() + if system == 'linux' + defaultpath = '/run/seatd.sock' + else + defaultpath = '/var/run/seatd.sock' + endif +endif + add_project_arguments( [ '-Wundef', @@ -32,6 +42,7 @@ add_project_arguments( '-D_XOPEN_SOURCE=700', '-D__BSD_VISIBLE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), + '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath) ], language: 'c', ) diff --git a/meson_options.txt b/meson_options.txt index 6e498c4..e32221a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,4 +4,4 @@ option('builtin', type: 'feature', value: 'disabled', description: 'builtin seat option('server', type: 'feature', value: 'enabled', description: 'seatd server') option('examples', type: 'feature', value: 'enabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') - +option('defaultpath', type: 'string', value: '', description: 'Default location for seatd socket (empty for default)') diff --git a/seatd/seatd.c b/seatd/seatd.c index bcd73b2..b601bce 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -17,7 +17,7 @@ #define LISTEN_BACKLOG 16 -static int open_socket(char *path, int uid, int gid) { +static int open_socket(const char *path, int uid, int gid) { union { struct sockaddr_un unix; struct sockaddr generic; @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { int c; int uid = 0, gid = 0; - char *socket_path = getenv("SEATD_SOCK"); + const char *socket_path = getenv("SEATD_SOCK"); while ((c = getopt(argc, argv, "vhs:g:u:")) != -1) { switch (c) { case 's': @@ -119,7 +119,7 @@ int main(int argc, char *argv[]) { } if (socket_path == NULL) { - socket_path = "/run/seatd.sock"; + socket_path = SEATD_DEFAULTPATH; struct stat st; if (stat(socket_path, &st) == 0) { log_info("removing leftover seatd socket"); From 0132841987f4a847e91d3592162340af425f3c55 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 00:53:01 +0200 Subject: [PATCH 041/211] libseat/seatd: Fix socket path bounds --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 1259308..f728a33 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -72,7 +72,7 @@ static int seatd_connect(void) { path = SEATD_DEFAULTPATH; } addr.unix.sun_family = AF_UNIX; - strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path); + strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (connect(fd, &addr.generic, size) == -1) { log_debugf("Could not connect to socket: %s", strerror(errno)); From 521d95349f6aced729192054e24cd04757f4f2ad Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 00:54:51 +0200 Subject: [PATCH 042/211] terminal: Fix VT numbering on FreeBSD FreeBSD adds one to the VT number returned by the GET_ACTIVE ioctl, so to match things up, the wrapper here subtracted by one. This lead to ttyv0 being named VT 0. This had the side-effect of VT numbering not matching expectations, and switching not behaving as intended. Align numbers with expectations, and move the required subtraction to terminal_open, so that VT 1 matches ttyv0. --- common/terminal.c | 60 +++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index e397357..ad54624 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -38,6 +38,38 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { const size_t prefix_len = sizeof(prefix) - 1; strcpy(path, prefix); + // The FreeBSD VT_GETACTIVE is implemented in the kernel as follows: + // + // static int + // vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, + // struct thread *td) + // { + // struct vt_window *vw = tm->tm_softc; + // struct vt_device *vd = vw->vw_device; + // ... + // switch (cmd) { + // ... + // case VT_GETACTIVE: + // *(int *)data = vd->vd_curwindow->vw_number + 1; + // return (0); + // ... + // } + // ... + // } + // + // The side-effect here being that the returned VT number is one + // greater than the internal VT number. The internal number is what is + // used to number the TTY device, while the external number is what we + // use in e.g. VT switching. + // + // We subtract one from the requested TTY number to compensate. If the + // user asked for TTY 0 (which is special on Linux), we just give them + // the first tty. + + if (tty > 0) { + tty--; + } + // The FreeBSD tty name is constructed in the kernel as follows: // // static void @@ -139,35 +171,11 @@ int terminal_current_vt(int fd) { return -1; } - // The FreeBSD VT_GETACTIVE is implemented in the kernel as follows: - // - // static int - // vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, - // struct thread *td) - // { - // struct vt_window *vw = tm->tm_softc; - // struct vt_device *vd = vw->vw_device; - // ... - // switch (cmd) { - // ... - // case VT_GETACTIVE: - // *(int *)data = vd->vd_curwindow->vw_number + 1; - // return (0); - // ... - // } - // ... - // } - // - // The side-effect here being that the returned VT number is one - // greater than the internal VT number, which is what is used for e.g. - // numbering the associated VT. To simplify things, we subtract one - // from the returned VT number before returning it. - - if (vt < 1) { + if (vt == -1) { log_errorf("invalid vt: %d", vt); return -1; } - return vt - 1; + return vt; #else #error Unsupported platform #endif From ba4c4226595598f6e3f9712eed6c04c49b7399e5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 00:59:48 +0200 Subject: [PATCH 043/211] seat: Use current VT for switch and ack --- seatd/seat.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index d11ca5a..16935cf 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -87,8 +87,8 @@ static void vt_close(struct seat *seat) { seat->cur_ttyfd = -1; } -static int vt_switch(int vt) { - int ttyfd = terminal_open(0); +static int vt_switch(struct seat *seat, int vt) { + int ttyfd = terminal_open(seat->cur_vt); if (ttyfd == -1) { log_errorf("could not open terminal: %s", strerror(errno)); return -1; @@ -99,8 +99,8 @@ static int vt_switch(int vt) { return 0; } -static int vt_ack(void) { - int tty0fd = terminal_open(0); +static int vt_ack(struct seat *seat) { + int tty0fd = terminal_open(seat->cur_vt); if (tty0fd == -1) { log_errorf("unable to open tty0: %s", strerror(errno)); return -1; @@ -575,7 +575,7 @@ int seat_set_next_session(struct client *client, int session) { if (seat->vt_bound) { log_infof("switching to VT %d from %d", session, seat->cur_vt); - if (vt_switch(session) == -1) { + if (vt_switch(seat, session) == -1) { log_error("could not switch VT"); return -1; } @@ -625,13 +625,14 @@ int seat_prepare_vt_switch(struct seat *seat) { log_debug("VT switch request on non VT-bound seat, ignoring"); return -1; } + seat_update_vt(seat); log_debug("acking VT switch"); if (seat->active_client != NULL) { seat_disable_client(seat->active_client); } - vt_ack(); + vt_ack(seat); seat->cur_vt = -1; return 0; } From be45c480ec0792c7dfb97e39b4f5369b75593ae8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 01:00:18 +0200 Subject: [PATCH 044/211] terminal: Ack both release and acquire Linux only requires acking release and ignores ack of acquire, but FreeBSD is more stringent and will patiently wait for both to be acked. Implement proper acking for both events. --- common/terminal.c | 18 ++++++++++++++---- include/seat.h | 2 +- include/terminal.h | 3 ++- seatd/seat.c | 20 ++++++++++++-------- seatd/server.c | 2 +- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index ad54624..7e4088d 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -199,7 +199,7 @@ int terminal_set_process_switching(int fd, bool enable) { } int terminal_switch_vt(int fd, int vt) { - log_debugf("switching to vt %d", vt); + log_debugf("switching to VT %d", vt); if (ioctl(fd, VT_ACTIVATE, vt) == -1) { log_errorf("could not activate VT: %s", strerror(errno)); return -1; @@ -208,10 +208,20 @@ int terminal_switch_vt(int fd, int vt) { return 0; } -int terminal_ack_switch(int fd) { - log_debug("acking vt switch"); +int terminal_ack_release(int fd) { + log_debug("acking VT release"); + if (ioctl(fd, VT_RELDISP, 1) == -1) { + log_errorf("could not ack VT release: %s", strerror(errno)); + return -1; + } + + return 0; +} + +int terminal_ack_acquire(int fd) { + log_debug("acking VT acquire"); if (ioctl(fd, VT_RELDISP, VT_ACKACQ) == -1) { - log_errorf("could not ack VT switch: %s", strerror(errno)); + log_errorf("could not ack VT acquire: %s", strerror(errno)); return -1; } diff --git a/include/seat.h b/include/seat.h index 2d269cc..cc21b7f 100644 --- a/include/seat.h +++ b/include/seat.h @@ -53,6 +53,6 @@ struct seat_device *seat_find_device(struct client *client, int device_id); int seat_set_next_session(struct client *client, int session); int seat_vt_activate(struct seat *seat); -int seat_prepare_vt_switch(struct seat *seat); +int seat_vt_release(struct seat *seat); #endif diff --git a/include/terminal.h b/include/terminal.h index 1215d8b..fb46ce3 100644 --- a/include/terminal.h +++ b/include/terminal.h @@ -8,7 +8,8 @@ int terminal_open(int vt); int terminal_set_process_switching(int fd, bool enable); int terminal_current_vt(int fd); int terminal_switch_vt(int fd, int vt); -int terminal_ack_switch(int fd); +int terminal_ack_release(int fd); +int terminal_ack_acquire(int fd); int terminal_set_keyboard(int fd, bool enable); int terminal_set_graphics(int fd, bool enable); diff --git a/seatd/seat.c b/seatd/seat.c index 16935cf..1ce44d0 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -99,13 +99,17 @@ static int vt_switch(struct seat *seat, int vt) { return 0; } -static int vt_ack(struct seat *seat) { +static int vt_ack(struct seat *seat, bool release) { int tty0fd = terminal_open(seat->cur_vt); if (tty0fd == -1) { log_errorf("unable to open tty0: %s", strerror(errno)); return -1; } - terminal_ack_switch(tty0fd); + if (release) { + terminal_ack_release(tty0fd); + } else { + terminal_ack_acquire(tty0fd); + } close(tty0fd); return 0; } @@ -610,29 +614,29 @@ int seat_vt_activate(struct seat *seat) { log_debug("VT activation on non VT-bound seat, ignoring"); return -1; } - - log_debug("switching session from VT activation"); seat_update_vt(seat); + log_debug("activating VT"); + vt_ack(seat, false); if (seat->active_client == NULL) { seat_activate(seat); } return 0; } -int seat_prepare_vt_switch(struct seat *seat) { +int seat_vt_release(struct seat *seat) { assert(seat); if (!seat->vt_bound) { - log_debug("VT switch request on non VT-bound seat, ignoring"); + log_debug("VT release request on non VT-bound seat, ignoring"); return -1; } seat_update_vt(seat); - log_debug("acking VT switch"); + log_debug("releasing VT"); if (seat->active_client != NULL) { seat_disable_client(seat->active_client); } - vt_ack(seat); + vt_ack(seat, true); seat->cur_vt = -1; return 0; } diff --git a/seatd/server.c b/seatd/server.c index 90aa610..acb366e 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -97,7 +97,7 @@ static int server_handle_vt_rel(int signal, void *data) { return -1; } - seat_prepare_vt_switch(seat); + seat_vt_release(seat); return 0; } From ca6478716dfdc623e4046d772f4473420a25b8a7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 22 Sep 2020 01:33:45 +0200 Subject: [PATCH 045/211] seat: Only close VT if no new session was found --- seatd/seat.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index 1ce44d0..66b623d 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -61,7 +61,10 @@ static void seat_update_vt(struct seat *seat) { static int vt_open(struct seat *seat, int vt) { assert(vt != -1); - assert(seat->cur_ttyfd == -1); + if (seat->cur_ttyfd != -1) { + terminal_set_process_switching(seat->cur_ttyfd, true); + close(seat->cur_ttyfd); + } seat->cur_ttyfd = terminal_open(vt); if (seat->cur_ttyfd == -1) { log_errorf("could not open terminal for vt %d: %s", vt, strerror(errno)); @@ -432,7 +435,7 @@ int seat_open_client(struct seat *seat, struct client *client) { } if (seat->vt_bound && vt_open(seat, client->session) == -1) { - return -1; + goto error; } for (struct linked_list *elem = client->devices.next; elem != &client->devices; @@ -446,11 +449,17 @@ int seat_open_client(struct seat *seat, struct client *client) { seat->active_client = client; if (client_send_enable_seat(client) == -1) { log_error("could not send enable signal"); - return -1; + goto error; } log_info("client successfully enabled"); return 0; + +error: + if (seat->vt_bound) { + vt_close(seat); + } + return -1; } int seat_close_client(struct client *client) { @@ -476,11 +485,10 @@ int seat_close_client(struct client *client) { seat->active_client = NULL; log_debug("closed client"); - if (seat->vt_bound) { + seat_activate(seat); + if (seat->vt_bound && seat->active_client == NULL) { vt_close(seat); } - - seat_activate(seat); return 0; } @@ -538,14 +546,16 @@ int seat_ack_disable_client(struct client *client) { client->pending_disable = false; log_debug("disabled client"); - if (seat->active_client == client) { - if (seat->vt_bound) { - vt_close(seat); - } - - seat->active_client = NULL; - seat_activate(seat); + if (seat->active_client != client) { + return 0; } + + seat->active_client = NULL; + seat_activate(seat); + if (seat->vt_bound && seat->active_client == NULL) { + vt_close(seat); + } + return 0; } From 7bf91a5f9fec57c798c1bb87ad6c2b71521f3188 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 28 Sep 2020 18:53:38 +0200 Subject: [PATCH 046/211] logind: close_device should not close fd --- libseat/backend/logind.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 98d7219..5afb77a 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -130,7 +130,6 @@ static int close_device(struct libseat *base, int device_id) { struct stat st = {0}; if (fstat(fd, &st) < 0) { log_errorf("Could not stat fd %d", fd); - close(fd); return -1; } if (dev_is_drm(st.st_rdev)) { @@ -138,7 +137,6 @@ static int close_device(struct libseat *base, int device_id) { log_debugf("DRM device closed, current total: %d", session->has_drm); assert(session->has_drm >= 0); } - close(fd); sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; From daffed09551eef1d46a25a3ed83bef43ef31ebdb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 10 Oct 2020 19:39:28 +0200 Subject: [PATCH 047/211] logind: Use seat_path for SwitchTo --- libseat/backend/logind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 5afb77a..d6bbd94 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -164,7 +164,7 @@ static int switch_session(struct libseat *base, int s) { sd_bus_error error = SD_BUS_ERROR_NULL; int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", - "/org/freedesktop/login1/seat/seat0", + session->seat_path, "org.freedesktop.login1.Seat", "SwitchTo", &error, &msg, "u", (uint32_t)s); if (ret < 0) { From 7d785ea9936a07608994e0264726d4e2d98e6919 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 11 Oct 2020 01:41:34 +0200 Subject: [PATCH 048/211] logind: clang-format --- libseat/backend/logind.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index d6bbd94..76297ce 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -163,8 +163,7 @@ static int switch_session(struct libseat *base, int s) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; - int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", - session->seat_path, + int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", session->seat_path, "org.freedesktop.login1.Seat", "SwitchTo", &error, &msg, "u", (uint32_t)s); if (ret < 0) { From 29ba210958c23a2a406d43f554b87dc1961af6e2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 11 Oct 2020 20:30:24 +0200 Subject: [PATCH 049/211] libseat: Better error reporting from open_seat --- libseat/libseat.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/libseat/libseat.c b/libseat/libseat.c index 11d3786..b1e8bb2 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -40,22 +40,39 @@ struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void * log_init(); char *backend_type = getenv("LIBSEAT_BACKEND"); + if (backend_type != NULL) { + const struct named_backend *iter = impls; + while (iter->backend != NULL && strcmp(backend_type, iter->name) != 0) { + iter++; + } + if (iter == NULL || iter->backend == NULL) { + log_errorf("No backend matched name '%s'", backend_type); + errno = EINVAL; + return NULL; + } + struct libseat *backend = iter->backend->open_seat(listener, data); + if (backend == NULL) { + log_errorf("Backend '%s' failed to open seat: %s", iter->name, + strerror(errno)); + return NULL; + } + log_infof("Seat opened with backend '%s'", iter->name); + return backend; + } + struct libseat *backend = NULL; for (const struct named_backend *iter = impls; iter->backend != NULL; iter++) { - if (backend_type != NULL && strcmp(backend_type, iter->name) != 0) { - continue; - } - log_infof("Trying backend '%s'", iter->name); backend = iter->backend->open_seat(listener, data); if (backend != NULL) { log_infof("Seat opened with backend '%s'", iter->name); - break; + return backend; } + log_infof("Backend '%s' failed to open seat, skipping", iter->name); } - if (backend == NULL) { - errno = ENOSYS; - } - return backend; + + log_error("No backend was able to open a seat"); + errno = ENOSYS; + return NULL; } int libseat_disable_seat(struct libseat *seat) { From e0945eb840f4b179f03eab781b9452f8faabab21 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 12 Oct 2020 17:58:20 +0200 Subject: [PATCH 050/211] connection: Add unittest --- meson.build | 9 +++ tests/connection.c | 176 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 tests/connection.c diff --git a/meson.build b/meson.build index 1ab3d87..a1c758c 100644 --- a/meson.build +++ b/meson.build @@ -203,6 +203,15 @@ test( ) ) +test( + 'connection', + executable( + 'connection_test', + ['common/connection.c', 'tests/connection.c'], + include_directories: [include_directories('.', 'include')], + ) +) + scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) if scdoc.found() diff --git a/tests/connection.c b/tests/connection.c new file mode 100644 index 0000000..551d799 --- /dev/null +++ b/tests/connection.c @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "connection.h" +#include "test.h" + +static void test_send_one_byte(void) { + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + struct connection c1 = {.fd = fds[0]}; + struct connection c2 = {.fd = fds[1]}; + + char in = 85, out = 0; + + test_assert(connection_put(&c1, &in, sizeof in) == 0); + test_assert(connection_flush(&c1) == sizeof in); + + test_assert(connection_read(&c2) == sizeof out); + test_assert(connection_pending(&c2) == sizeof out); + test_assert(connection_get(&c2, &out, sizeof out) == sizeof out); + test_assert(out == in); + + test_assert(connection_pending(&c2) == 0); + close(fds[0]); + close(fds[1]); +} + +static void test_short_read(void) { + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + struct connection c1 = {.fd = fds[0]}; + struct connection c2 = {.fd = fds[1]}; + + char in = 85, out = 0; + int out_large = 0; + + test_assert(connection_put(&c1, &in, sizeof in) == 0); + test_assert(connection_flush(&c1) > 0); + + test_assert(connection_read(&c2) > 0); + + test_assert(connection_pending(&c2) == sizeof out); + test_assert(connection_get(&c2, &out, sizeof out_large) == -1); + test_assert(errno == EAGAIN); + + test_assert(connection_pending(&c2) == sizeof out); + test_assert(connection_get(&c2, &out, sizeof out) == sizeof out); + + test_assert(out == in); + + test_assert(connection_pending(&c2) == 0); + close(fds[0]); + close(fds[1]); +} + +static void test_long_write(void) { + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + struct connection c1 = {.fd = fds[0]}; + struct connection c2 = {.fd = fds[1]}; + + char in[CONNECTION_BUFFER_SIZE + 1]; + memset(in, 0, sizeof in); + + test_assert(connection_put(&c1, &in, sizeof in) == -1); + test_assert(errno = EAGAIN); + + test_assert(connection_read(&c2) == -1 && errno == EAGAIN); + test_assert(connection_pending(&c2) == 0); + close(fds[0]); + close(fds[1]); +} + +static void test_send_one_int(void) { + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + struct connection c1 = {.fd = fds[0]}; + struct connection c2 = {.fd = fds[1]}; + + int in = 0xDEADBEEF, out = 0; + + test_assert(connection_put(&c1, &in, sizeof in) == 0); + test_assert(connection_flush(&c1) == sizeof in); + + test_assert(connection_read(&c2) == sizeof out); + test_assert(connection_pending(&c2) == sizeof out); + test_assert(connection_get(&c2, &out, sizeof out) == sizeof out); + + test_assert(out == in); + + test_assert(connection_pending(&c2) == 0); + close(fds[0]); + close(fds[1]); +} + +static void test_restore(void) { + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + struct connection c1 = {.fd = fds[0]}; + struct connection c2 = {.fd = fds[1]}; + + int in = 0xDEADBEEF, out = 0; + + test_assert(connection_put(&c1, &in, sizeof in) == 0); + test_assert(connection_flush(&c1) == sizeof in); + + test_assert(connection_read(&c2) == sizeof out); + test_assert(connection_pending(&c2) == sizeof out); + test_assert(connection_get(&c2, &out, sizeof out) == sizeof out); + + test_assert(out == in); + + test_assert(connection_pending(&c2) == 0); + + connection_restore(&c2, sizeof out); + test_assert(connection_pending(&c2) == sizeof out); + test_assert(connection_get(&c2, &out, sizeof out) == sizeof out); + + test_assert(out == in); + + test_assert(connection_pending(&c2) == 0); + close(fds[0]); + close(fds[1]); +} + +static void test_send_variable_sequence(void) { + int fds[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + struct connection c1 = {.fd = fds[0]}; + struct connection c2 = {.fd = fds[1]}; + + char in1 = 85, out1 = 0; + int in2 = 0xDEADBEEF, out2 = 0; + uint64_t in3 = 0xCAFEDEADBEEF, out3 = 0; + char in4 = 85, out4 = 0; + + test_assert(connection_put(&c1, &in1, sizeof in1) == 0); + test_assert(connection_put(&c1, &in2, sizeof in2) == 0); + test_assert(connection_put(&c1, &in3, sizeof in3) == 0); + test_assert(connection_put(&c1, &in4, sizeof in4) == 0); + test_assert(connection_flush(&c1) > 0); + + test_assert(connection_read(&c2) > 0); + test_assert(connection_pending(&c2) > 0); + test_assert(connection_get(&c2, &out1, sizeof out1) == sizeof out1); + test_assert(connection_get(&c2, &out2, sizeof out2) == sizeof out2); + test_assert(connection_get(&c2, &out3, sizeof out3) == sizeof out3); + test_assert(connection_get(&c2, &out4, sizeof out4) == sizeof out4); + + test_assert(out1 == in1); + test_assert(out2 == in2); + test_assert(out3 == in3); + test_assert(out4 == in4); + + test_assert(connection_pending(&c2) == 0); + close(fds[0]); + close(fds[1]); +} + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + test_run(test_send_one_byte); + test_run(test_short_read); + test_run(test_long_write); + test_run(test_send_one_int); + test_run(test_restore); + test_run(test_send_variable_sequence); +} From 26eff322d407f6e15823bbbbf883f2ed097f3f0b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 16 Oct 2020 21:38:32 +0200 Subject: [PATCH 051/211] readme: Update mailing list link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 114845d..4a0c8e1 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,4 @@ Instead of giving user shell developers more work, libseat aims to make supporti ## I want more -Go to #kennylevinsen @ chat.freenode.net to discuss, or use [~kennylevinsen/public-inbox@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/public-inbox). +Go to #kennylevinsen @ chat.freenode.net to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). From 271305a15f33c4be7396372fa043fdb6d6765bf9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 19 Oct 2020 23:11:07 +0200 Subject: [PATCH 052/211] Bump version to 0.4.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a1c758c..cc13546 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.3.0', + version: '0.4.0', license: 'MIT', meson_version: '>=0.53.0', default_options: [ From 2185e8f180f30a87d1a1f76505d9133e27cda1d6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 3 Nov 2020 15:22:46 +0100 Subject: [PATCH 053/211] ci: Clean up build manifests --- .builds/alpine.yml | 15 ++++----------- .builds/archlinux.yml | 12 +++--------- .builds/freebsd.yml | 13 ++++--------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index e048494..048e3ef 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -9,25 +9,18 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - cd seatd - meson build -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd - build: | - cd seatd ninja -C build - unittest: | - cd seatd ninja -C build test - scan-build: | - cd seatd ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-seatd.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-builtin.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh - check-format: | - cd seatd ninja -C build clang-format - git diff --exit-code + git -C seatd diff --exit-code diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 419254f..301e88b 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,21 +9,15 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - cd seatd - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build + meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build seatd - build: | - cd seatd ninja -C build - unittest: | - cd seatd ninja -C build test - scan-build: | - cd seatd ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-seatd.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-builtin.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index ca9a3c1..e13566a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -5,20 +5,15 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - cd seatd - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd - build: | - cd seatd ninja -C build - unittest: | - cd seatd ninja -C build test - smoketest: | - cd seatd rm -rf build - meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build + meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd ninja -C build - timeout -s KILL 30s ./.builds/smoketest-seatd.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-builtin.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh From 3c80a9db9628aec7009d7e51c1a3393bc801078c Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 21 Nov 2020 16:59:01 +0100 Subject: [PATCH 054/211] libseat: log error when failing to open socket The most common pain point I've seen with people trying out seat is forgetting to add themselves to whatever group the distro has chosen to own the socket. Logging this error and path of the socket should make it easier to tell why things aren't working. --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index f728a33..e4ce7c4 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -75,7 +75,7 @@ static int seatd_connect(void) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (connect(fd, &addr.generic, size) == -1) { - log_debugf("Could not connect to socket: %s", strerror(errno)); + log_errorf("Could not connect to socket %s: %s", path, strerror(errno)); close(fd); return -1; }; From df8494af61356be3b2c575bd3f6a33090a286248 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 Nov 2020 16:48:18 +0100 Subject: [PATCH 055/211] poller: Retry poll immediately on EINTR There is nothing for us to dispatch unless we wake on an fd, so just retry poll if it fails with EINTR instead of doing a full dispatch loop. --- seatd/poller.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/seatd/poller.c b/seatd/poller.c index 267929b..ceadb24 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -315,8 +315,10 @@ int poller_poll(struct poller *poller) { poller->dirty = false; } - if (poll(poller->pollfds, poller->fd_event_sources, -1) == -1 && errno != EINTR) { - return -1; + while (poll(poller->pollfds, poller->fd_event_sources, -1) == -1) { + if (errno != EINTR) { + return -1; + } } dispatch(poller); From e0782a825e769c67dab8222911414765c0839d24 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 Nov 2020 01:03:37 +0100 Subject: [PATCH 056/211] client: More robust handling of client links --- seatd/client.c | 10 ++++------ seatd/seat.c | 7 +------ seatd/server.c | 3 +-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/seatd/client.c b/seatd/client.c index fcb238d..5cacae7 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -70,6 +70,7 @@ struct client *client_create(struct server *server, int client_fd) { client->server = server; client->connection.fd = client_fd; linked_list_init(&client->devices); + linked_list_insert(&server->idle_clients, &client->link); return client; } @@ -80,14 +81,9 @@ void client_destroy(struct client *client) { close(client->connection.fd); client->connection.fd = -1; } + linked_list_remove(&client->link); if (client->seat != NULL) { - // This should also close and remove all devices. This unlinks - // the client. seat_remove_client(client); - } else { - // If we are not a member of a seat, we will be on the idle - // clients list, so unlink the client manually. - linked_list_remove(&client->link); } if (client->event_source != NULL) { event_source_fd_destroy(client->event_source); @@ -149,6 +145,7 @@ static int handle_open_seat(struct client *client) { log_errorf("unable to add client to target seat: %s", strerror(errno)); return -1; } + linked_list_insert(&seat->clients, &client->link); size_t seat_name_len = strlen(seat_name); @@ -177,6 +174,7 @@ static int handle_close_seat(struct client *client) { return -1; } + linked_list_remove(&client->link); if (seat_remove_client(client) == -1) { log_error("unable to remove client from seat"); return -1; diff --git a/seatd/seat.c b/seatd/seat.c index 66b623d..b530a36 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -149,9 +149,8 @@ int seat_add_client(struct seat *seat, struct client *client) { log_debugf("registered client %p as session %d", (void *)client, client->session); client->seat = seat; - - linked_list_insert(&seat->clients, &client->link); log_debug("added client"); + return 0; } @@ -160,10 +159,6 @@ int seat_remove_client(struct client *client) { assert(client->seat); struct seat *seat = client->seat; - - // We must first remove the client to avoid reactivation - linked_list_remove(&client->link); - if (seat->next_client == client) { seat->next_client = NULL; } diff --git a/seatd/server.c b/seatd/server.c index acb366e..3ca73b3 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -132,13 +132,12 @@ int server_add_client(struct server *server, int fd) { client->event_source = poller_add_fd(&server->poller, fd, EVENT_READABLE, client_handle_connection, client); if (client->event_source == NULL) { - client_destroy(client); log_errorf("could not add client socket to poller: %s", strerror(errno)); + client_destroy(client); return -1; } log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, client->gid); - linked_list_insert(&server->idle_clients, &client->link); return 0; } From 0d5f48f4339b984c2f5c44287984072506461fc9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 Nov 2020 01:49:09 +0100 Subject: [PATCH 057/211] terminal: Improve logging --- common/terminal.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 7e4088d..67cb1a1 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -182,7 +182,7 @@ int terminal_current_vt(int fd) { } int terminal_set_process_switching(int fd, bool enable) { - log_debug("setting process switching"); + log_debugf("setting process switching to %d", enable); struct vt_mode mode = { .mode = enable ? VT_PROCESS : VT_AUTO, .waitv = 0, @@ -192,7 +192,8 @@ int terminal_set_process_switching(int fd, bool enable) { }; if (ioctl(fd, VT_SETMODE, &mode) == -1) { - log_errorf("could not set VT mode: %s", strerror(errno)); + log_errorf("could not set VT mode to %s process switching: %s", + enable ? "enable" : "disable", strerror(errno)); return -1; } return 0; @@ -201,7 +202,7 @@ int terminal_set_process_switching(int fd, bool enable) { int terminal_switch_vt(int fd, int vt) { log_debugf("switching to VT %d", vt); if (ioctl(fd, VT_ACTIVATE, vt) == -1) { - log_errorf("could not activate VT: %s", strerror(errno)); + log_errorf("could not activate VT %d: %s", vt, strerror(errno)); return -1; } @@ -231,7 +232,8 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("setting KD keyboard state to %d", enable); if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { - log_errorf("could not set KD keyboard mode: %s", strerror(errno)); + log_errorf("could not set KD keyboard mode to %s: %s", + enable ? "enabled" : "disabled", strerror(errno)); return -1; } #if defined(__FreeBSD__) @@ -246,7 +248,8 @@ int terminal_set_keyboard(int fd, bool enable) { cfmakeraw(&tios); } if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) { - log_errorf("could not set terminal mode: %s", strerror(errno)); + log_errorf("could not set terminal mode to %s: %s", enable ? "sane" : "raw", + strerror(errno)); return -1; } #endif @@ -256,7 +259,8 @@ 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); if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) { - log_errorf("could not set KD graphics mode: %s", strerror(errno)); + log_errorf("could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", + strerror(errno)); return -1; } return 0; From 1dbf1002055627f473ac891d1ea309f1f3ddc2c3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 24 Nov 2020 13:12:31 +0100 Subject: [PATCH 058/211] logind: switch_session should return 0 on success It currently returned -1 on failure and 1 on success. The API is intended to return -1 on failure and 0 on success, so fix that. --- libseat/backend/logind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 76297ce..f0cadce 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -172,7 +172,7 @@ static int switch_session(struct libseat *base, int s) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret < 0 ? -1 : 0; } static int disable_seat(struct libseat *base) { From e3a357badea76a6f67f00b07c15dc67dd08be560 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 19:01:56 +0000 Subject: [PATCH 059/211] libseat/backend/logind: stop waiting for CanGraphical Upstream says compositors should wait for DRM nodes using udev instead. --- libseat/backend/logind.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index f0cadce..c9a22c0 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -39,7 +39,6 @@ struct backend_logind { char *path; char *seat_path; - bool can_graphical; bool active; bool initial_setup; int has_drm; @@ -384,8 +383,7 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error goto error; } - if ((is_session && strcmp(s, "Active") == 0) || - (is_seat && strcmp(s, "CanGraphical"))) { + if (is_session && strcmp(s, "Active") == 0) { int ret; ret = sd_bus_message_enter_container(msg, 'v', "b"); if (ret < 0) { @@ -399,11 +397,7 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error } log_debugf("%s state changed: %d", s, value); - if (is_session) { - set_active(session, value); - } else { - session->can_graphical = value; - } + set_active(session, value); return 0; } else { sd_bus_message_skip(msg, "{sv}"); @@ -427,12 +421,10 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error // PropertiesChanged arg 3: changed properties without values sd_bus_message_enter_container(msg, 'a', "s"); while ((ret = sd_bus_message_read_basic(msg, 's', &s)) > 0) { - if ((is_session && strcmp(s, "Active") == 0) || - (is_seat && strcmp(s, "CanGraphical"))) { + if (is_session && strcmp(s, "Active") == 0) { sd_bus_error error = SD_BUS_ERROR_NULL; - const char *obj = is_session ? "org.freedesktop.login1.Session" - : "org.freedesktop.login1.Seat"; - const char *field = is_session ? "Active" : "CanGraphical"; + const char *obj = "org.freedesktop.login1.Session"; + const char *field = "Active"; bool value; ret = sd_bus_get_property_trivial(session->bus, "org.freedesktop.login1", session->path, obj, field, &error, 'b', @@ -443,11 +435,7 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error } log_debugf("%s state changed: %d", field, value); - if (is_session) { - set_active(session, value); - } else { - session->can_graphical = value; - } + set_active(session, value); return 0; } } @@ -650,14 +638,6 @@ static struct libseat *logind_open_seat(struct libseat_seat_listener *listener, goto error; } - backend->can_graphical = sd_seat_can_graphical(backend->seat); - while (!backend->can_graphical) { - if (poll_connection(backend, -1) == -1) { - log_errorf("Could not poll connection: %s", strerror(errno)); - goto error; - } - } - const char *env = getenv("XDG_SESSION_TYPE"); if (env != NULL) { set_type(backend, env); From e99e7d71f75394b68b581e86af4bdbdb43ee64ea Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 8 Dec 2020 16:38:17 +0100 Subject: [PATCH 060/211] client: Do not use SOL_SOCKET for LOCAL_PEERCRED This is wrong, and leads to LOCAL_PEERCRED being interpreted as SO_DEBUG. 0 should be used instead. See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246189. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 5cacae7..edea23c 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -37,7 +37,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { #elif defined(__FreeBSD__) struct xucred cred; socklen_t len = sizeof cred; - if (getsockopt(fd, SOL_SOCKET, LOCAL_PEERCRED, &cred, &len) == -1) { + if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) == -1) { return -1; } *pid = -1; From 9b3bdcb12d0dea1cc5b96eefbc083114556df565 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 8 Dec 2020 16:42:13 +0100 Subject: [PATCH 061/211] client: Use cr_pid if available This is only available on FreeBSD 13, so test for that version. --- seatd/client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/seatd/client.c b/seatd/client.c index edea23c..162f4ba 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -40,7 +40,11 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) == -1) { return -1; } +#if __FreeBSD_version >= 1300030 + pid = cred.cr_pid; +#else *pid = -1; +#endif *uid = cred.cr_uid; *gid = cred.cr_ngroups > 0 ? cred.cr_groups[0] : (gid_t)-1; return 0; From 3755eea668cf7162ff861df9e8545ea5095792c1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 10 Dec 2020 10:07:43 +0100 Subject: [PATCH 062/211] client: Fix typo in cr_pid usage --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 162f4ba..a5a11ab 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -41,7 +41,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { return -1; } #if __FreeBSD_version >= 1300030 - pid = cred.cr_pid; + *pid = cred.cr_pid; #else *pid = -1; #endif From 1ececbbf361a227fa6449f51904f97f37763b5a4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 14 Dec 2020 23:41:00 +0100 Subject: [PATCH 063/211] simpletest: Close fd after closing device --- examples/simpletest/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simpletest/main.c b/examples/simpletest/main.c index 0ec1c91..aeeace2 100644 --- a/examples/simpletest/main.c +++ b/examples/simpletest/main.c @@ -57,8 +57,8 @@ int main(int argc, char *argv[]) { return 1; } - close(fd); libseat_close_device(backend, device); + close(fd); libseat_close_seat(backend); return 0; } From 61b086511f86e8cc93528818ec0070c3c02a642f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 14 Dec 2020 23:40:44 +0100 Subject: [PATCH 064/211] logind: Send ReleaseControl when closing seat This is not strictly speaking necessary as detaching from the bus should trigger this automatically, but elogind apparently has issues with this. Doing this explicitly does no harm, so let's just do that. --- libseat/backend/logind.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index c9a22c0..0ae95b1 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -46,6 +46,7 @@ struct backend_logind { const struct seat_impl logind_impl; static struct backend_logind *backend_logind_from_libseat_backend(struct libseat *base); +static void release_control(struct backend_logind *backend); static void destroy(struct backend_logind *backend) { assert(backend); @@ -61,6 +62,7 @@ static void destroy(struct backend_logind *backend) { static int close_seat(struct libseat *base) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); + release_control(backend); destroy(backend); return 0; } @@ -280,6 +282,21 @@ static bool take_control(struct backend_logind *session) { return ret >= 0; } +static void release_control(struct backend_logind *session) { + sd_bus_message *msg = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + + int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", session->path, + "org.freedesktop.login1.Session", "ReleaseControl", &error, + &msg, ""); + if (ret < 0) { + log_errorf("Could not release control of session: %s", error.message); + } + + sd_bus_error_free(&error); + sd_bus_message_unref(msg); +} + static void set_active(struct backend_logind *backend, bool active) { if (backend->active == active) { return; @@ -652,9 +669,7 @@ static struct libseat *logind_open_seat(struct libseat_seat_listener *listener, return &backend->base; error: - if (backend != NULL) { - destroy(backend); - } + destroy(backend); return NULL; } From b1f7ec1c4d753d0135cb88347efbc11c7039b2cb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Feb 2021 21:03:42 +0100 Subject: [PATCH 065/211] seat: Remove unused arg from seat_deactive_device --- seatd/seat.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index b530a36..a14eddd 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -302,9 +302,7 @@ done: return device; } -static int seat_deactivate_device(struct client *client, struct seat_device *seat_device) { - assert(client); - assert(client->seat); +static int seat_deactivate_device(struct seat_device *seat_device) { assert(seat_device && seat_device->fd > 0); if (!seat_device->active) { @@ -347,7 +345,7 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { linked_list_remove(&seat_device->link); if (seat_device->fd != -1) { - seat_deactivate_device(client, seat_device); + seat_deactivate_device(seat_device); close(seat_device->fd); } free(seat_device->path); @@ -512,7 +510,7 @@ static int seat_disable_client(struct client *client) { for (struct linked_list *elem = client->devices.next; elem != &client->devices; elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; - if (seat_deactivate_device(client, device) == -1) { + if (seat_deactivate_device(device) == -1) { log_errorf("unable to deactivate '%s': %s", device->path, strerror(errno)); } } From 45bab8b258b1cb0ba68eff3bfc3913e1e5d84b7d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 15:13:18 +0100 Subject: [PATCH 066/211] client: Replace pending_disable with state enum This simplifies logic in seat handling. --- include/client.h | 10 +++++++++- seatd/client.c | 1 + seatd/seat.c | 41 ++++++++++++++++++++--------------------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/client.h b/include/client.h index 3b1f105..8746bea 100644 --- a/include/client.h +++ b/include/client.h @@ -10,6 +10,14 @@ struct server; +enum client_state { + CLIENT_NEW, + CLIENT_ACTIVE, + CLIENT_PENDING_DISABLE, + CLIENT_DISABLED, + CLIENT_CLOSED +}; + struct client { struct linked_list link; // seat::clients struct server *server; @@ -22,7 +30,7 @@ struct client { struct seat *seat; int session; - bool pending_disable; + enum client_state state; struct linked_list devices; }; diff --git a/seatd/client.c b/seatd/client.c index a5a11ab..949bbd8 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -73,6 +73,7 @@ struct client *client_create(struct server *server, int client_fd) { client->session = -1; client->server = server; client->connection.fd = client_fd; + client->state = CLIENT_NEW; linked_list_init(&client->devices); linked_list_insert(&server->idle_clients, &client->link); return client; diff --git a/seatd/seat.c b/seatd/seat.c index a14eddd..0893db7 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -200,15 +200,12 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { assert(strlen(path) > 0); struct seat *seat = client->seat; - if (client != seat->active_client) { - errno = EPERM; - return NULL; - } - - if (client->pending_disable) { + if (client->state != CLIENT_ACTIVE) { + log_error("client is not active"); errno = EPERM; return NULL; } + assert(seat->active_client == client); char sanitized_path[PATH_MAX]; if (realpath(path, sanitized_path) == NULL) { @@ -419,10 +416,15 @@ done: int seat_open_client(struct seat *seat, struct client *client) { assert(seat); assert(client); - assert(!client->pending_disable); + + if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { + log_error("client is not new or disabled"); + errno = EALREADY; + return -1; + } if (seat->active_client != NULL) { - log_error("client already active"); + log_error("seat already has active client"); errno = EBUSY; return -1; } @@ -439,6 +441,7 @@ int seat_open_client(struct seat *seat, struct client *client) { } } + client->state = CLIENT_ACTIVE; seat->active_client = client; if (client_send_enable_seat(client) == -1) { log_error("could not send enable signal"); @@ -474,7 +477,7 @@ int seat_close_client(struct client *client) { } } - client->pending_disable = false; + client->state = CLIENT_CLOSED; seat->active_client = NULL; log_debug("closed client"); @@ -491,17 +494,12 @@ static int seat_disable_client(struct client *client) { struct seat *seat = client->seat; - if (seat->active_client != client) { + if (client->state != CLIENT_ACTIVE) { log_error("client not active"); errno = EBUSY; return -1; } - - if (client->pending_disable) { - log_error("client already pending disable"); - errno = EBUSY; - return -1; - } + 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 @@ -515,7 +513,7 @@ static int seat_disable_client(struct client *client) { } } - client->pending_disable = true; + client->state = CLIENT_PENDING_DISABLE; if (client_send_disable_seat(seat->active_client) == -1) { log_error("could not send disable event"); return -1; @@ -530,13 +528,13 @@ int seat_ack_disable_client(struct client *client) { assert(client->seat); struct seat *seat = client->seat; - if (!client->pending_disable) { + if (client->state != CLIENT_PENDING_DISABLE) { log_error("client not pending disable"); errno = EBUSY; return -1; } - client->pending_disable = false; + client->state = CLIENT_DISABLED; log_debug("disabled client"); if (seat->active_client != client) { @@ -558,11 +556,12 @@ int seat_set_next_session(struct client *client, int session) { struct seat *seat = client->seat; - if (seat->active_client != client || client->pending_disable) { - log_error("client not active or pending disable"); + if (client->state != CLIENT_ACTIVE) { + log_error("client is not active"); errno = EPERM; return -1; } + assert(seat->active_client == client); if (session <= 0) { log_errorf("invalid session value: %d", session); From 65d91351ab8c2336601369b718cdc517ecbe6041 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 15:23:00 +0100 Subject: [PATCH 067/211] seatd: Tear down VT when disabled client closes If a client closed while it was disabled, the VT would not be torn down. If the user navigated back to the VT it belonged to, they would be stuck. When a client is disabled, open the fd for the VT it belonged to and perform regular teardown on it. --- include/seat.h | 1 - seatd/seat.c | 67 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/include/seat.h b/include/seat.h index cc21b7f..fa5873c 100644 --- a/include/seat.h +++ b/include/seat.h @@ -44,7 +44,6 @@ void seat_destroy(struct seat *seat); int seat_add_client(struct seat *seat, struct client *client); int seat_remove_client(struct client *client); int seat_open_client(struct seat *seat, struct client *client); -int seat_close_client(struct client *client); int seat_ack_disable_client(struct client *client); struct seat_device *seat_open_device(struct client *client, const char *path); diff --git a/seatd/seat.c b/seatd/seat.c index 0893db7..3e134b1 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -18,6 +18,8 @@ #include "seat.h" #include "terminal.h" +static int seat_close_client(struct client *client); + struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); if (seat == NULL) { @@ -77,19 +79,33 @@ static int vt_open(struct seat *seat, int vt) { return 0; } +static void vt_close_fd(int fd) { + terminal_set_process_switching(fd, true); + terminal_set_keyboard(fd, true); + terminal_set_graphics(fd, false); +} + static void vt_close(struct seat *seat) { if (seat->cur_ttyfd == -1) { return; } - terminal_set_process_switching(seat->cur_ttyfd, true); - terminal_set_keyboard(seat->cur_ttyfd, true); - terminal_set_graphics(seat->cur_ttyfd, false); - + vt_close_fd(seat->cur_ttyfd); close(seat->cur_ttyfd); seat->cur_ttyfd = -1; } +static int vt_close_num(int vt) { + int ttyfd = terminal_open(vt); + if (ttyfd == -1) { + log_errorf("could not open terminal %s", strerror(errno)); + return -1; + } + vt_close_fd(ttyfd); + close(ttyfd); + return 0; +} + static int vt_switch(struct seat *seat, int vt) { int ttyfd = terminal_open(seat->cur_vt); if (ttyfd == -1) { @@ -168,9 +184,7 @@ int seat_remove_client(struct client *client) { seat_close_device(client, device); } - if (seat->active_client == client) { - seat_close_client(client); - } + seat_close_client(client); client->seat = NULL; log_debug("removed client"); @@ -458,18 +472,12 @@ error: return -1; } -int seat_close_client(struct client *client) { +static int seat_close_client(struct client *client) { assert(client); assert(client->seat); struct seat *seat = client->seat; - if (seat->active_client != client) { - log_error("client not active"); - errno = EBUSY; - return -1; - } - while (!linked_list_empty(&client->devices)) { struct seat_device *device = (struct seat_device *)client->devices.next; if (seat_close_device(client, device) == -1) { @@ -477,14 +485,29 @@ int seat_close_client(struct client *client) { } } + bool was_current = seat->active_client == client; + if (was_current) { + seat->active_client = NULL; + seat_activate(seat); + } + + if (seat->vt_bound) { + if (was_current && seat->active_client == NULL) { + // This client was current, but there were no clients + // waiting to take this VT, so clean it up. + log_debug("closing active VT"); + vt_close(seat); + } else if (!was_current && client->state != CLIENT_CLOSED) { + // This client was not current, but as the client was + // running, we need to clean up the VT. + log_debug("closing inactive VT"); + vt_close_num(client->session); + } + } + client->state = CLIENT_CLOSED; - seat->active_client = NULL; log_debug("closed client"); - seat_activate(seat); - if (seat->vt_bound && seat->active_client == NULL) { - vt_close(seat); - } return 0; } @@ -543,10 +566,10 @@ int seat_ack_disable_client(struct client *client) { seat->active_client = NULL; seat_activate(seat); - if (seat->vt_bound && seat->active_client == NULL) { - vt_close(seat); - } + // If we're VT-bound, we've either de-activated a client on a foreign + // VT, in which case we need to do nothing, or disabled the current VT, + // in which case seat_activate would just immediately re-enable it. return 0; } From 152ee5102a10cf363222dc23ed9dd65ace2ebfc4 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 26 Feb 2021 20:34:27 -0800 Subject: [PATCH 068/211] meson: ignore 'man-pages' if 'server' is disabled `seatd.1` is the only man page, so it's not necessary to install it or require scdoc when the server is not built. --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cc13546..5b06e57 100644 --- a/meson.build +++ b/meson.build @@ -212,7 +212,11 @@ test( ) ) -scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) +if get_option('server').enabled() + scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) +else + scdoc = disabler() +endif if scdoc.found() sh = find_program('sh', native: true) From da3cbcc9436321e59b9e11fa8caa624e3d71ea35 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 18:23:53 +0100 Subject: [PATCH 069/211] libseat: Fix typo in doc string --- include/libseat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libseat.h b/include/libseat.h index 891cb86..5375cd6 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -131,7 +131,7 @@ int libseat_get_fd(struct libseat *seat); * milliseconds that might occur. * * Returns a positive number signifying processed internal messages on success. - * Returns 0-if no messages were processed. Returns -1 and sets errno on error. + * Returns 0 if no messages were processed. Returns -1 and sets errno on error. */ int libseat_dispatch(struct libseat *seat, int timeout); From 6cf751af2b0313bc9b78ea9e56dc72ec91325935 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 18:24:54 +0100 Subject: [PATCH 070/211] logind: Fix return values from close_device/get_fd --- libseat/backend/logind.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 0ae95b1..c6f2aaf 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -151,7 +151,7 @@ static int close_device(struct libseat *base, int device_id) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret < 0 ? -1 : 0; } static int switch_session(struct libseat *base, int s) { @@ -183,7 +183,13 @@ static int disable_seat(struct libseat *base) { static int get_fd(struct libseat *base) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); - return sd_bus_get_fd(backend->bus); + int fd = sd_bus_get_fd(backend->bus); + if (fd >= 0) { + return fd; + } + + errno = -fd; + return -1; } static int poll_connection(struct backend_logind *backend, int timeout) { From ff38ea595af7bdac330b44b01443742c015bf426 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Nov 2020 02:18:45 +0100 Subject: [PATCH 071/211] seatd: Set errno in seat_add_client --- seatd/seat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/seatd/seat.c b/seatd/seat.c index 3e134b1..4def100 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -139,16 +139,19 @@ int seat_add_client(struct seat *seat, struct client *client) { if (client->seat != NULL) { log_error("cannot add client: client is already a member of a seat"); + errno = EBUSY; return -1; } if (seat->vt_bound && seat->active_client != NULL) { log_error("cannot add client: seat is vt_bound and an active client already exists"); + errno = EBUSY; return -1; } if (client->session != -1) { log_error("cannot add client: client cannot be reused"); + errno = EINVAL; return -1; } @@ -156,6 +159,7 @@ int seat_add_client(struct seat *seat, struct client *client) { seat_update_vt(seat); if (seat->cur_vt == -1) { log_error("could not determine VT for client"); + errno = EINVAL; return -1; } client->session = seat->cur_vt; From 456d08dc834df5d980d6f95e9158b6b0673ebc2f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 19:57:20 +0100 Subject: [PATCH 072/211] Convert a few debug logs to error logs --- libseat/backend/seatd.c | 2 +- seatd/seat.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index e4ce7c4..2dea3ca 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -585,7 +585,7 @@ static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, } if (geteuid() != 0) { - log_debug("Built-in seatd instance requires root privileges"); + log_error("Built-in seatd instance requires root privileges"); return NULL; } diff --git a/seatd/seat.c b/seatd/seat.c index 4def100..5ed83b5 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -276,7 +276,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { switch (type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(fd) == -1) { - log_debugf("drm_set_master failed: %s", strerror(errno)); + log_errorf("could not make device fd drm master: %s", strerror(errno)); } break; case SEAT_DEVICE_TYPE_EVDEV: @@ -326,13 +326,13 @@ static int seat_deactivate_device(struct seat_device *seat_device) { switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_drop_master(seat_device->fd) == -1) { - log_debugf("drm_drop_master failed: %s", strerror(errno)); + log_errorf("could not revoke drm master on device fd: %s", strerror(errno)); return -1; } break; case SEAT_DEVICE_TYPE_EVDEV: if (evdev_revoke(seat_device->fd) == -1) { - log_debugf("evdev_revoke failed: %s", strerror(errno)); + log_errorf("could not revoke evdev on device fd: %s", strerror(errno)); return -1; } break; @@ -379,7 +379,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(seat_device->fd) == -1) { - log_debugf("drmset_master failed: %s", strerror(errno)); + log_errorf("could not make device fd drm master: %s", strerror(errno)); } seat_device->active = true; break; From ffd6f039f8b29ec9f53f6b88a432f8257a5489e2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:02:59 +0100 Subject: [PATCH 073/211] seatd: Clean up debug logs a bit --- seatd/seat.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index 5ed83b5..c34cfe1 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -34,7 +34,11 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { free(seat); return NULL; } - log_debugf("created seat '%s' (vt_bound: %d)", seat_name, vt_bound); + if (vt_bound) { + log_infof("created VT-bound seat '%s'", seat_name); + } else { + log_infof("created seat '%s'", seat_name); + } return seat; } @@ -144,7 +148,7 @@ int seat_add_client(struct seat *seat, struct client *client) { } if (seat->vt_bound && seat->active_client != NULL) { - log_error("cannot add client: seat is vt_bound and an active client already exists"); + log_error("cannot add client: seat is VT-bound and an active client already exists"); errno = EBUSY; return -1; } @@ -166,10 +170,9 @@ int seat_add_client(struct seat *seat, struct client *client) { } else { client->session = seat->session_cnt++; } - log_debugf("registered client %p as session %d", (void *)client, client->session); client->seat = seat; - log_debug("added client"); + log_infof("added client %d", client->session); return 0; } @@ -191,7 +194,7 @@ int seat_remove_client(struct client *client) { seat_close_client(client); client->seat = NULL; - log_debug("removed client"); + log_infof("removed client %d", client->session); return 0; } @@ -311,8 +314,8 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { linked_list_insert(&client->devices, &device->link); done: - log_debugf("seat: %p, client: %p, path: '%s', device_id: %d, ref_cnt: %d", (void *)seat, - (void *)client, path, device_id, device->ref_cnt); + log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", seat->seat_name, + client->session, path, device_id, device->ref_cnt); return device; } @@ -349,8 +352,8 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { assert(client->seat); assert(seat_device && seat_device->fd != -1); - log_debugf("seat: %p, client: %p, path: '%s', device_id: %d, ref_cnt: %d", - (void *)client->seat, (void *)client, seat_device->path, seat_device->device_id, + log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", + client->seat->seat_name, client->session, seat_device->path, seat_device->device_id, seat_device->ref_cnt); seat_device->ref_cnt--; @@ -403,18 +406,20 @@ static int seat_activate(struct seat *seat) { struct client *next_client = NULL; if (seat->next_client != NULL) { - log_info("activating next queued client"); + log_debug("activating next queued client"); next_client = seat->next_client; seat->next_client = NULL; } else if (linked_list_empty(&seat->clients)) { log_info("no clients on seat to activate"); return -1; + } else if (seat->vt_bound && seat->cur_vt == -1) { + return -1; } else if (seat->vt_bound) { for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; elem = elem->next) { struct client *client = (struct client *)elem; if (client->session == seat->cur_vt) { - log_infof("activating client belonging to VT %d", seat->cur_vt); + log_debugf("activating client belonging to VT %d", seat->cur_vt); next_client = client; goto done; } @@ -423,7 +428,7 @@ static int seat_activate(struct seat *seat) { log_infof("no clients belonging to VT %d to activate", seat->cur_vt); return -1; } else { - log_info("activating first client on seat"); + log_debug("activating first client on seat"); next_client = (struct client *)seat->clients.next; } @@ -436,18 +441,21 @@ int seat_open_client(struct seat *seat, struct client *client) { assert(client); if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { - log_error("client is not new or disabled"); + log_errorf("could not enable client %d: client is not new or disabled", + client->session); errno = EALREADY; return -1; } if (seat->active_client != NULL) { - log_error("seat already has active client"); + log_errorf("could not enable client %d: seat already has active client", + client->session); errno = EBUSY; return -1; } if (seat->vt_bound && vt_open(seat, client->session) == -1) { + log_errorf("could not open VT for client %d", client->session); goto error; } @@ -455,18 +463,19 @@ int seat_open_client(struct seat *seat, struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_activate_device(client, device) == -1) { - log_errorf("unable to activate '%s': %s", device->path, strerror(errno)); + log_errorf("unable to activate '%s' for client %d: %s", + device->path, client->session, strerror(errno)); } } client->state = CLIENT_ACTIVE; seat->active_client = client; if (client_send_enable_seat(client) == -1) { - log_error("could not send enable signal"); + log_errorf("could not send enable signal to client %d", client->session); goto error; } - log_info("client successfully enabled"); + log_infof("enabled client %d", client->session); return 0; error: @@ -510,7 +519,7 @@ static int seat_close_client(struct client *client) { } client->state = CLIENT_CLOSED; - log_debug("closed client"); + log_infof("closed client %d", client->session); return 0; } @@ -546,7 +555,7 @@ static int seat_disable_client(struct client *client) { return -1; } - log_debug("disabling client"); + log_infof("disabling client %d", client->session); return 0; } @@ -562,7 +571,7 @@ int seat_ack_disable_client(struct client *client) { } client->state = CLIENT_DISABLED; - log_debug("disabled client"); + log_infof("disabled client %d", client->session); if (seat->active_client != client) { return 0; @@ -607,7 +616,7 @@ int seat_set_next_session(struct client *client, int session) { } if (seat->vt_bound) { - log_infof("switching to VT %d from %d", session, seat->cur_vt); + log_infof("switching to VT %d from VT %d", session, seat->cur_vt); if (vt_switch(seat, session) == -1) { log_error("could not switch VT"); return -1; From cedd64c283794c5b6593f308cddde2cdab7c2bcf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:22:45 +0100 Subject: [PATCH 074/211] client: Remove link if seat_add_client succeeds Removing the link before before means that we can return without a link, resulting in a double-remove. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 949bbd8..286a3ae 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -145,11 +145,11 @@ static int handle_open_seat(struct client *client) { return -1; } - linked_list_remove(&client->link); if (seat_add_client(seat, client) == -1) { log_errorf("unable to add client to target seat: %s", strerror(errno)); return -1; } + linked_list_remove(&client->link); linked_list_insert(&seat->clients, &client->link); size_t seat_name_len = strlen(seat_name); From e173691cfd0fd06baec924f5df90eb1e9f4e8fb5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:44:31 +0100 Subject: [PATCH 075/211] seatd: Close cur_ttyfd in seat_destroy This fd would only still be set after closing clients if no clients were active on the current VT. --- seatd/seat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/seatd/seat.c b/seatd/seat.c index c34cfe1..c737979 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -19,6 +19,8 @@ #include "terminal.h" static int seat_close_client(struct client *client); +static void vt_close(struct seat *seat); + struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); @@ -49,7 +51,7 @@ void seat_destroy(struct seat *seat) { assert(client->seat == seat); client_destroy(client); } - assert(seat->cur_ttyfd == -1); + vt_close(seat); linked_list_remove(&seat->link); free(seat->seat_name); free(seat); From 3a6a7e6b4c52119ddd0828808a210ae69c4392fe Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:48:03 +0100 Subject: [PATCH 076/211] clang-format --- seatd/seat.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index c737979..9c9f7eb 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -21,7 +21,6 @@ static int seat_close_client(struct client *client); static void vt_close(struct seat *seat); - struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); if (seat == NULL) { @@ -316,8 +315,8 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { linked_list_insert(&client->devices, &device->link); done: - log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", seat->seat_name, - client->session, path, device_id, device->ref_cnt); + log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", + seat->seat_name, client->session, path, device_id, device->ref_cnt); return device; } @@ -355,8 +354,8 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { assert(seat_device && seat_device->fd != -1); log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", - client->seat->seat_name, client->session, seat_device->path, seat_device->device_id, - seat_device->ref_cnt); + client->seat->seat_name, client->session, seat_device->path, + seat_device->device_id, seat_device->ref_cnt); seat_device->ref_cnt--; if (seat_device->ref_cnt > 0) { @@ -444,14 +443,14 @@ int seat_open_client(struct seat *seat, struct client *client) { if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { log_errorf("could not enable client %d: client is not new or disabled", - client->session); + client->session); errno = EALREADY; return -1; } if (seat->active_client != NULL) { log_errorf("could not enable client %d: seat already has active client", - client->session); + client->session); errno = EBUSY; return -1; } @@ -465,8 +464,8 @@ int seat_open_client(struct seat *seat, struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_activate_device(client, device) == -1) { - log_errorf("unable to activate '%s' for client %d: %s", - device->path, client->session, strerror(errno)); + log_errorf("unable to activate '%s' for client %d: %s", device->path, + client->session, strerror(errno)); } } From 79b90788bd1b836e3d5449722e40e4628326574d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 1 Mar 2021 01:11:37 +0100 Subject: [PATCH 077/211] log: Remove function name from log --- include/log.h | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/include/log.h b/include/log.h index 9aee33c..f5f423e 100644 --- a/include/log.h +++ b/include/log.h @@ -17,27 +17,21 @@ #define __FILENAME__ __FILE__ #endif -#define log_infof(fmt, ...) \ - _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] %s: " fmt, __FILENAME__, __LINE__, __func__, \ - __VA_ARGS__) +#define log_infof(fmt, ...) \ + _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) -#define log_info(str) \ - _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] %s: %s", __FILENAME__, __LINE__, __func__, str) +#define log_info(str) _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] %s", __FILENAME__, __LINE__, str) -#define log_errorf(fmt, ...) \ - _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s: " fmt, __FILENAME__, __LINE__, __func__, \ - __VA_ARGS__) +#define log_errorf(fmt, ...) \ + _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) -#define log_error(str) \ - _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s: %s", __FILENAME__, __LINE__, __func__, str) +#define log_error(str) _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s", __FILENAME__, __LINE__, str) #ifdef DEBUG -#define log_debugf(fmt, ...) \ - _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s: " fmt, __FILENAME__, __LINE__, __func__, \ - __VA_ARGS__) +#define log_debugf(fmt, ...) \ + _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) -#define log_debug(str) \ - _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s: %s", __FILENAME__, __LINE__, __func__, str) +#define log_debug(str) _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s", __FILENAME__, __LINE__, str) #else #define log_debugf(fmt, ...) #define log_debug(str) From e4c28227ec1de65ee6ce5bb52412a2a2cf4c0628 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Mar 2021 00:14:32 +0100 Subject: [PATCH 078/211] Normalize log texts a bit --- common/terminal.c | 38 +++++++------- seatd/client.c | 72 ++++++++++++++------------ seatd/seat.c | 128 ++++++++++++++++++++++------------------------ seatd/seatd.c | 18 +++---- seatd/server.c | 14 ++--- 5 files changed, 135 insertions(+), 135 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 67cb1a1..6274957 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -141,12 +141,12 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { int terminal_open(int vt) { char path[TTYPATHLEN]; if (get_tty_path(vt, path) == -1) { - log_errorf("could not generate tty path: %s", strerror(errno)); + log_errorf("Could not generate tty path: %s", strerror(errno)); return -1; } int fd = open(path, O_RDWR | O_NOCTTY); if (fd == -1) { - log_errorf("could not open target tty: %s", strerror(errno)); + log_errorf("Could not open target tty: %s", strerror(errno)); return -1; } return fd; @@ -158,7 +158,7 @@ int terminal_current_vt(int fd) { int res = ioctl(fd, VT_GETSTATE, &st); close(fd); if (res == -1) { - log_errorf("could not retrieve VT state: %s", strerror(errno)); + log_errorf("Could not retrieve VT state: %s", strerror(errno)); return -1; } return st.v_active; @@ -167,12 +167,12 @@ int terminal_current_vt(int fd) { int res = ioctl(fd, VT_GETACTIVE, &vt); close(fd); if (res == -1) { - log_errorf("could not retrieve VT state: %s", strerror(errno)); + log_errorf("Could not retrieve VT state: %s", strerror(errno)); return -1; } if (vt == -1) { - log_errorf("invalid vt: %d", vt); + log_errorf("Invalid VT: %d", vt); return -1; } return vt; @@ -182,7 +182,7 @@ int terminal_current_vt(int fd) { } int terminal_set_process_switching(int fd, bool enable) { - log_debugf("setting process switching to %d", enable); + log_debugf("Setting process switching to %d", enable); struct vt_mode mode = { .mode = enable ? VT_PROCESS : VT_AUTO, .waitv = 0, @@ -192,7 +192,7 @@ int terminal_set_process_switching(int fd, bool enable) { }; if (ioctl(fd, VT_SETMODE, &mode) == -1) { - log_errorf("could not set VT mode to %s process switching: %s", + log_errorf("Could not set VT mode to %s process switching: %s", enable ? "enable" : "disable", strerror(errno)); return -1; } @@ -200,9 +200,9 @@ int terminal_set_process_switching(int fd, bool enable) { } int terminal_switch_vt(int fd, int vt) { - log_debugf("switching to VT %d", vt); + log_debugf("Switching to VT %d", vt); if (ioctl(fd, VT_ACTIVATE, vt) == -1) { - log_errorf("could not activate VT %d: %s", vt, strerror(errno)); + log_errorf("Could not activate VT %d: %s", vt, strerror(errno)); return -1; } @@ -210,9 +210,9 @@ int terminal_switch_vt(int fd, int vt) { } int terminal_ack_release(int fd) { - log_debug("acking VT release"); + log_debug("Acking VT release"); if (ioctl(fd, VT_RELDISP, 1) == -1) { - log_errorf("could not ack VT release: %s", strerror(errno)); + log_errorf("Could not ack VT release: %s", strerror(errno)); return -1; } @@ -220,9 +220,9 @@ int terminal_ack_release(int fd) { } int terminal_ack_acquire(int fd) { - log_debug("acking VT acquire"); + log_debug("Acking VT acquire"); if (ioctl(fd, VT_RELDISP, VT_ACKACQ) == -1) { - log_errorf("could not ack VT acquire: %s", strerror(errno)); + log_errorf("Could not ack VT acquire: %s", strerror(errno)); return -1; } @@ -230,16 +230,16 @@ int terminal_ack_acquire(int fd) { } int terminal_set_keyboard(int fd, bool enable) { - log_debugf("setting KD keyboard state to %d", enable); + log_debugf("Setting KD keyboard state to %d", enable); if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { - log_errorf("could not set KD keyboard mode to %s: %s", + log_errorf("Could not set KD keyboard mode to %s: %s", enable ? "enabled" : "disabled", strerror(errno)); return -1; } #if defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { - log_errorf("could not set get terminal mode: %s", strerror(errno)); + log_errorf("Could not set get terminal mode: %s", strerror(errno)); return -1; } if (enable) { @@ -248,7 +248,7 @@ int terminal_set_keyboard(int fd, bool enable) { cfmakeraw(&tios); } if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) { - log_errorf("could not set terminal mode to %s: %s", enable ? "sane" : "raw", + log_errorf("Could not set terminal mode to %s: %s", enable ? "sane" : "raw", strerror(errno)); return -1; } @@ -257,9 +257,9 @@ 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); + log_debugf("Setting KD graphics state to %d", enable); if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) { - log_errorf("could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", + log_errorf("Could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", strerror(errno)); return -1; } diff --git a/seatd/client.c b/seatd/client.c index 286a3ae..d0f321d 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -120,7 +120,7 @@ static int client_send_error(struct client *client, int error_code) { if (connection_put(&client->connection, &errheader, sizeof errheader) == -1 || connection_put(&client->connection, &errmsg, sizeof errmsg) == -1) { - log_error("could not send error to client"); + log_errorf("Could not send error to client: %s", strerror(errno)); return -1; } return 0; @@ -135,18 +135,18 @@ static char *client_get_seat_name(struct client *client) { static int handle_open_seat(struct client *client) { char *seat_name = client_get_seat_name(client); if (seat_name == NULL) { - log_error("could not get name of target seat"); + log_error("Could not get name of target seat"); return -1; } struct seat *seat = server_get_seat(client->server, seat_name); if (seat == NULL) { - log_error("unable to find seat by name"); + log_errorf("Could not find seat named %s", seat_name); return -1; } if (seat_add_client(seat, client) == -1) { - log_errorf("unable to add client to target seat: %s", strerror(errno)); + log_errorf("Could not add client to target seat: %s", strerror(errno)); return -1; } linked_list_remove(&client->link); @@ -165,7 +165,7 @@ static int handle_open_seat(struct client *client) { if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_put(&client->connection, &rmsg, sizeof rmsg) == -1 || connection_put(&client->connection, seat_name, seat_name_len) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -175,13 +175,13 @@ static int handle_open_seat(struct client *client) { static int handle_close_seat(struct client *client) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } linked_list_remove(&client->link); if (seat_remove_client(client) == -1) { - log_error("unable to remove client from seat"); + log_error("Could not remove client from seat"); return -1; } linked_list_insert(&client->server->idle_clients, &client->link); @@ -192,7 +192,7 @@ static int handle_close_seat(struct client *client) { }; if (connection_put(&client->connection, &header, sizeof header) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -201,25 +201,25 @@ static int handle_close_seat(struct client *client) { static int handle_open_device(struct client *client, char *path) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } struct seat_device *device = seat_open_device(client, path); if (device == NULL) { - log_errorf("could not open device: %s", strerror(errno)); + log_errorf("Could not open device: %s", strerror(errno)); goto fail; } int dupfd = dup(device->fd); if (dupfd == -1) { - log_errorf("could not dup fd: %s", strerror(errno)); + log_errorf("Could not dup fd: %s", strerror(errno)); seat_close_device(client, device); goto fail; } if (connection_put_fd(&client->connection, dupfd) == -1) { - log_errorf("unable to queue fd for sending: %s", strerror(errno)); + log_errorf("Could not queue fd for sending: %s", strerror(errno)); return -1; } @@ -233,7 +233,7 @@ static int handle_open_device(struct client *client, char *path) { if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_put(&client->connection, &msg, sizeof msg) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -245,19 +245,19 @@ fail: static int handle_close_device(struct client *client, int device_id) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } struct seat_device *device = seat_find_device(client, device_id); if (device == NULL) { - log_error("no such device"); + log_error("No such device"); errno = EBADF; goto fail; } if (seat_close_device(client, device) == -1) { - log_errorf("could not close device: %s", strerror(errno)); + log_errorf("Could not close device: %s", strerror(errno)); goto fail; } @@ -267,7 +267,7 @@ static int handle_close_device(struct client *client, int device_id) { }; if (connection_put(&client->connection, &header, sizeof header) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -279,7 +279,7 @@ fail: static int handle_switch_session(struct client *client, int session) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } @@ -295,7 +295,7 @@ error: static int handle_disable_seat(struct client *client) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } @@ -314,7 +314,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s switch (opcode) { case CLIENT_OPEN_SEAT: { if (size != 0) { - log_error("protocol error: invalid open_seat message"); + log_error("Protocol error: invalid open_seat message"); return -1; } res = handle_open_seat(client); @@ -322,7 +322,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s } case CLIENT_CLOSE_SEAT: { if (size != 0) { - log_error("protocol error: invalid close_seat message"); + log_error("Protocol error: invalid close_seat message"); return -1; } res = handle_close_seat(client); @@ -333,11 +333,11 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s struct proto_client_open_device msg; if (sizeof msg > size || connection_get(&client->connection, &msg, sizeof msg) == -1 || sizeof msg + msg.path_len > size || msg.path_len > MAX_PATH_LEN) { - log_error("protocol error: invalid open_device message"); + log_error("Protocol error: invalid open_device message"); return -1; } if (connection_get(&client->connection, path, msg.path_len) == -1) { - log_error("protocol error: invalid open_device message"); + log_error("Protocol error: invalid open_device message"); return -1; } @@ -347,7 +347,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s case CLIENT_CLOSE_DEVICE: { struct proto_client_close_device msg; if (sizeof msg > size || connection_get(&client->connection, &msg, sizeof msg) == -1) { - log_error("protocol error: invalid close_device message"); + log_error("Protocol error: invalid close_device message"); return -1; } @@ -357,7 +357,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s case CLIENT_SWITCH_SESSION: { struct proto_client_switch_session msg; if (sizeof msg > size || connection_get(&client->connection, &msg, sizeof msg) == -1) { - log_error("protocol error: invalid switch_session message"); + log_error("Protocol error: invalid switch_session message"); return -1; } @@ -366,14 +366,14 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s } case CLIENT_DISABLE_SEAT: { if (size != 0) { - log_error("protocol error: invalid disable_seat message"); + log_error("Protocol error: invalid disable_seat message"); return -1; } res = handle_disable_seat(client); break; } default: - log_errorf("protocol error: unknown opcode: %d", opcode); + log_errorf("Protocol error: unknown opcode: %d", opcode); res = -1; break; } @@ -390,7 +390,7 @@ int client_send_disable_seat(struct client *client) { }; if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_flush(&client->connection) == -1) { - log_error("unable to send event"); + log_errorf("Could not send event: %s", strerror(errno)); return -1; } return 0; @@ -403,7 +403,7 @@ int client_send_enable_seat(struct client *client) { }; if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_flush(&client->connection) == -1) { - log_error("unable to send event"); + log_errorf("Could not send event: %s", strerror(errno)); return -1; } return 0; @@ -414,18 +414,18 @@ int client_handle_connection(int fd, uint32_t mask, void *data) { struct client *client = data; if (mask & EVENT_ERROR) { - log_error("connection error"); + log_error("Connection error"); goto fail; } if (mask & EVENT_HANGUP) { - log_info("client disconnected"); + log_info("Client disconnected"); goto fail; } if (mask & EVENT_WRITABLE) { int len = connection_flush(&client->connection); if (len == -1 && errno != EAGAIN) { - log_error("could not flush client connection"); + log_errorf("Could not flush client connection: %s", strerror(errno)); goto fail; } else if (len >= 0) { event_source_fd_update(client->event_source, EVENT_READABLE); @@ -434,8 +434,12 @@ int client_handle_connection(int fd, uint32_t mask, void *data) { if (mask & EVENT_READABLE) { int len = connection_read(&client->connection); - if (len == 0 || (len == -1 && errno != EAGAIN)) { - log_error("could not read client connection"); + if (len == -1 && errno != EAGAIN) { + log_errorf("Could not read client connection: %s", strerror(errno)); + goto fail; + } + if (len == 0) { + log_error("Could not read client connection: zero-length read"); goto fail; } diff --git a/seatd/seat.c b/seatd/seat.c index 9c9f7eb..9ad4af2 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -36,9 +36,9 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { return NULL; } if (vt_bound) { - log_infof("created VT-bound seat '%s'", seat_name); + log_infof("Created VT-bound seat %s", seat_name); } else { - log_infof("created seat '%s'", seat_name); + log_infof("Created seat %s", seat_name); } return seat; } @@ -59,7 +59,7 @@ void seat_destroy(struct seat *seat) { static void seat_update_vt(struct seat *seat) { int tty0fd = terminal_open(0); if (tty0fd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); + log_errorf("Could not open tty0 to update VT: %s", strerror(errno)); return; } seat->cur_vt = terminal_current_vt(tty0fd); @@ -74,7 +74,7 @@ static int vt_open(struct seat *seat, int vt) { } seat->cur_ttyfd = terminal_open(vt); if (seat->cur_ttyfd == -1) { - log_errorf("could not open terminal for vt %d: %s", vt, strerror(errno)); + log_errorf("Could not open terminal for VT %d: %s", vt, strerror(errno)); return -1; } @@ -103,7 +103,7 @@ static void vt_close(struct seat *seat) { static int vt_close_num(int vt) { int ttyfd = terminal_open(vt); if (ttyfd == -1) { - log_errorf("could not open terminal %s", strerror(errno)); + log_errorf("Could not open terminal to clean up VT %d: %s", vt, strerror(errno)); return -1; } vt_close_fd(ttyfd); @@ -114,7 +114,7 @@ static int vt_close_num(int vt) { static int vt_switch(struct seat *seat, int vt) { int ttyfd = terminal_open(seat->cur_vt); if (ttyfd == -1) { - log_errorf("could not open terminal: %s", strerror(errno)); + log_errorf("Could not open terminal to switch to VT %d: %s", vt, strerror(errno)); return -1; } terminal_set_process_switching(ttyfd, true); @@ -126,7 +126,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); if (tty0fd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); + log_errorf("Could not open tty0 to ack VT signal: %s", strerror(errno)); return -1; } if (release) { @@ -143,19 +143,19 @@ int seat_add_client(struct seat *seat, struct client *client) { assert(client); if (client->seat != NULL) { - log_error("cannot add client: client is already a member of a seat"); + log_error("Could not add client: client is already a member of a seat"); errno = EBUSY; return -1; } if (seat->vt_bound && seat->active_client != NULL) { - log_error("cannot add client: seat is VT-bound and an active client already exists"); + log_error("Could not add client: seat is VT-bound and has an active client"); errno = EBUSY; return -1; } if (client->session != -1) { - log_error("cannot add client: client cannot be reused"); + log_error("Could not add client: client cannot be reused"); errno = EINVAL; return -1; } @@ -163,7 +163,7 @@ int seat_add_client(struct seat *seat, struct client *client) { if (seat->vt_bound) { seat_update_vt(seat); if (seat->cur_vt == -1) { - log_error("could not determine VT for client"); + log_error("Could not determine VT for client"); errno = EINVAL; return -1; } @@ -173,7 +173,7 @@ int seat_add_client(struct seat *seat, struct client *client) { } client->seat = seat; - log_infof("added client %d", client->session); + log_infof("Added client %d to %s", client->session, seat->seat_name); return 0; } @@ -195,7 +195,7 @@ int seat_remove_client(struct client *client) { seat_close_client(client); client->seat = NULL; - log_infof("removed client %d", client->session); + log_infof("Removed client %d from %s", client->session, seat->seat_name); return 0; } @@ -222,8 +222,10 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { assert(strlen(path) > 0); struct seat *seat = client->seat; + log_debugf("Opening device %s for client %d on %s", path, client->session, seat->seat_name); + if (client->state != CLIENT_ACTIVE) { - log_error("client is not active"); + log_error("Could open device: client is not active"); errno = EPERM; return NULL; } @@ -231,7 +233,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { char sanitized_path[PATH_MAX]; if (realpath(path, sanitized_path) == NULL) { - log_errorf("invalid path '%s': %s", path, strerror(errno)); + log_errorf("Could not canonicalize path %s: %s", path, strerror(errno)); return NULL; } @@ -241,7 +243,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { } else if (path_is_drm(sanitized_path)) { type = SEAT_DEVICE_TYPE_DRM; } else { - log_errorf("invalid path '%s'", sanitized_path); + log_errorf("%s is not a supported device type ", sanitized_path); errno = ENOENT; return NULL; } @@ -266,34 +268,34 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { } if (device_count >= MAX_SEAT_DEVICES) { - log_error("max seat devices exceeded"); + log_error("Client exceeded max seat devices"); errno = EMFILE; return NULL; } int fd = open(sanitized_path, O_RDWR | O_NOCTTY | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK); if (fd == -1) { - log_errorf("could not open file: %s", strerror(errno)); + log_errorf("Could not open file: %s", strerror(errno)); return NULL; } switch (type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(fd) == -1) { - log_errorf("could not make device fd drm master: %s", strerror(errno)); + log_errorf("Could not make device fd drm master: %s", strerror(errno)); } break; case SEAT_DEVICE_TYPE_EVDEV: // Nothing to do here break; default: - log_error("invalid seat device type"); + log_error("Invalid seat device type"); abort(); } device = calloc(1, sizeof(struct seat_device)); if (device == NULL) { - log_errorf("could not alloc device for '%s': %s", sanitized_path, strerror(errno)); + log_errorf("Allocation failed: %s", strerror(errno)); close(fd); errno = ENOMEM; return NULL; @@ -301,7 +303,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { device->path = strdup(sanitized_path); if (device->path == NULL) { - log_errorf("could not dup path for '%s': %s", sanitized_path, strerror(errno)); + log_errorf("Allocation failed: %s", strerror(errno)); close(fd); free(device); return NULL; @@ -315,8 +317,6 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { linked_list_insert(&client->devices, &device->link); done: - log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", - seat->seat_name, client->session, path, device_id, device->ref_cnt); return device; } @@ -330,18 +330,18 @@ static int seat_deactivate_device(struct seat_device *seat_device) { switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_drop_master(seat_device->fd) == -1) { - log_errorf("could not revoke drm master on device fd: %s", strerror(errno)); + log_errorf("Could not revoke drm master on device fd: %s", strerror(errno)); return -1; } break; case SEAT_DEVICE_TYPE_EVDEV: if (evdev_revoke(seat_device->fd) == -1) { - log_errorf("could not revoke evdev on device fd: %s", strerror(errno)); + log_errorf("Could not revoke evdev on device fd: %s", strerror(errno)); return -1; } break; default: - log_error("invalid seat device type"); + log_error("Invalid seat device type"); abort(); } seat_device->active = false; @@ -353,9 +353,8 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { assert(client->seat); assert(seat_device && seat_device->fd != -1); - log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", - client->seat->seat_name, client->session, seat_device->path, - seat_device->device_id, seat_device->ref_cnt); + log_debugf("Closing device %s for client %d on %s", seat_device->path, client->session, + client->seat->seat_name); seat_device->ref_cnt--; if (seat_device->ref_cnt > 0) { @@ -383,7 +382,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(seat_device->fd) == -1) { - log_errorf("could not make device fd drm master: %s", strerror(errno)); + log_errorf("Could not make device fd drm master: %s", strerror(errno)); } seat_device->active = true; break; @@ -391,7 +390,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ errno = EINVAL; return -1; default: - log_error("invalid seat device type"); + log_error("Invalid seat device type"); abort(); } @@ -407,11 +406,11 @@ static int seat_activate(struct seat *seat) { struct client *next_client = NULL; if (seat->next_client != NULL) { - log_debug("activating next queued client"); + log_debugf("Activating next queued client on %s", seat->seat_name); next_client = seat->next_client; seat->next_client = NULL; } else if (linked_list_empty(&seat->clients)) { - log_info("no clients on seat to activate"); + log_infof("No clients on %s to activate", seat->seat_name); return -1; } else if (seat->vt_bound && seat->cur_vt == -1) { return -1; @@ -420,16 +419,16 @@ static int seat_activate(struct seat *seat) { elem = elem->next) { struct client *client = (struct client *)elem; if (client->session == seat->cur_vt) { - log_debugf("activating client belonging to VT %d", seat->cur_vt); + log_debugf("Activating client belonging to VT %d", seat->cur_vt); next_client = client; goto done; } } - log_infof("no clients belonging to VT %d to activate", seat->cur_vt); + log_infof("No clients belonging to VT %d to activate", seat->cur_vt); return -1; } else { - log_debug("activating first client on seat"); + log_debugf("Activating first client on %s", seat->seat_name); next_client = (struct client *)seat->clients.next; } @@ -442,21 +441,19 @@ int seat_open_client(struct seat *seat, struct client *client) { assert(client); if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { - log_errorf("could not enable client %d: client is not new or disabled", - client->session); + log_error("Could not enable client: client is not new or disabled"); errno = EALREADY; return -1; } if (seat->active_client != NULL) { - log_errorf("could not enable client %d: seat already has active client", - client->session); + log_error("Could not enable client: seat already has an active client"); errno = EBUSY; return -1; } if (seat->vt_bound && vt_open(seat, client->session) == -1) { - log_errorf("could not open VT for client %d", client->session); + log_error("Could not open VT for client"); goto error; } @@ -464,19 +461,18 @@ int seat_open_client(struct seat *seat, struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_activate_device(client, device) == -1) { - log_errorf("unable to activate '%s' for client %d: %s", device->path, - client->session, strerror(errno)); + log_errorf("Could not activate %s: %s", device->path, strerror(errno)); } } client->state = CLIENT_ACTIVE; seat->active_client = client; if (client_send_enable_seat(client) == -1) { - log_errorf("could not send enable signal to client %d", client->session); + log_error("Could not send enable signal to client"); goto error; } - log_infof("enabled client %d", client->session); + log_infof("Opened client %d on %s", client->session, seat->seat_name); return 0; error: @@ -495,7 +491,7 @@ static int seat_close_client(struct client *client) { while (!linked_list_empty(&client->devices)) { struct seat_device *device = (struct seat_device *)client->devices.next; if (seat_close_device(client, device) == -1) { - log_errorf("unable to close '%s': %s", device->path, strerror(errno)); + log_errorf("Could not close %s: %s", device->path, strerror(errno)); } } @@ -509,18 +505,18 @@ static int seat_close_client(struct client *client) { if (was_current && seat->active_client == NULL) { // This client was current, but there were no clients // waiting to take this VT, so clean it up. - log_debug("closing active VT"); + log_debug("Closing active VT"); vt_close(seat); } else if (!was_current && client->state != CLIENT_CLOSED) { // This client was not current, but as the client was // running, we need to clean up the VT. - log_debug("closing inactive VT"); + log_debug("Closing inactive VT"); vt_close_num(client->session); } } client->state = CLIENT_CLOSED; - log_infof("closed client %d", client->session); + log_infof("Closed client %d on %s", client->session, seat->seat_name); return 0; } @@ -532,7 +528,7 @@ static int seat_disable_client(struct client *client) { struct seat *seat = client->seat; if (client->state != CLIENT_ACTIVE) { - log_error("client not active"); + log_error("Could not disable client: client is not active"); errno = EBUSY; return -1; } @@ -546,17 +542,17 @@ static int seat_disable_client(struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_deactivate_device(device) == -1) { - log_errorf("unable to deactivate '%s': %s", device->path, strerror(errno)); + log_errorf("Could not deactivate %s: %s", device->path, strerror(errno)); } } client->state = CLIENT_PENDING_DISABLE; if (client_send_disable_seat(seat->active_client) == -1) { - log_error("could not send disable event"); + log_error("Could not send disable event"); return -1; } - log_infof("disabling client %d", client->session); + log_infof("Disabling client %d on %s", client->session, seat->seat_name); return 0; } @@ -566,13 +562,13 @@ int seat_ack_disable_client(struct client *client) { struct seat *seat = client->seat; if (client->state != CLIENT_PENDING_DISABLE) { - log_error("client not pending disable"); + log_error("Could not ack disable: client is not pending disable"); errno = EBUSY; return -1; } client->state = CLIENT_DISABLED; - log_infof("disabled client %d", client->session); + log_infof("Disabled client %d on %s", client->session, seat->seat_name); if (seat->active_client != client) { return 0; @@ -594,32 +590,32 @@ int seat_set_next_session(struct client *client, int session) { struct seat *seat = client->seat; if (client->state != CLIENT_ACTIVE) { - log_error("client is not active"); + log_error("Could not set next session: client is not active"); errno = EPERM; return -1; } assert(seat->active_client == client); if (session <= 0) { - log_errorf("invalid session value: %d", session); + log_errorf("Could not set next session: invalid session value %d", session); errno = EINVAL; return -1; } if (session == client->session) { - log_info("requested session is already active"); + log_info("Could not set next session: requested session is already active"); return 0; } if (seat->next_client != NULL) { - log_info("switch is already queued"); + log_info("Could not set next session: switch is already queued"); return 0; } if (seat->vt_bound) { - log_infof("switching to VT %d from VT %d", session, seat->cur_vt); + log_infof("Switching from VT %d to VT %d", seat->cur_vt, session); if (vt_switch(seat, session) == -1) { - log_error("could not switch VT"); + log_error("Could not switch VT"); return -1; } return 0; @@ -636,12 +632,12 @@ int seat_set_next_session(struct client *client, int session) { } if (target == NULL) { - log_error("no valid switch available"); + log_error("Could not set next session: no such client"); errno = EINVAL; return -1; } - log_infof("queuing switch client with session %d", session); + log_infof("Queuing switch to client %d on %s", session, seat->seat_name); seat->next_client = target; seat_disable_client(seat->active_client); return 0; @@ -654,7 +650,7 @@ int seat_vt_activate(struct seat *seat) { return -1; } seat_update_vt(seat); - log_debug("activating VT"); + log_debug("Activating VT"); vt_ack(seat, false); if (seat->active_client == NULL) { seat_activate(seat); @@ -670,7 +666,7 @@ int seat_vt_release(struct seat *seat) { } seat_update_vt(seat); - log_debug("releasing VT"); + log_debug("Releasing VT"); if (seat->active_client != NULL) { seat_disable_client(seat->active_client); } diff --git a/seatd/seatd.c b/seatd/seatd.c index b601bce..278f857 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -24,7 +24,7 @@ static int open_socket(const char *path, int uid, int gid) { } addr = {{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)); + log_errorf("Could not create socket: %s", strerror(errno)); return -1; } @@ -32,21 +32,21 @@ static int open_socket(const char *path, int uid, int gid) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (bind(fd, &addr.generic, size) == -1) { - log_errorf("could not bind socket: %s", strerror(errno)); + log_errorf("Could not bind socket: %s", strerror(errno)); close(fd); return -1; } if (listen(fd, LISTEN_BACKLOG) == -1) { - log_errorf("could not listen on socket: %s", strerror(errno)); + log_errorf("Could not listen on socket: %s", strerror(errno)); close(fd); return -1; } if (uid != 0 || gid != 0) { if (chown(path, uid, gid) == -1) { - log_errorf("could not chown socket to uid %d, gid %d: %s", uid, gid, + log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); } else if (chmod(path, 0770) == -1) { - log_errorf("could not chmod socket: %s", strerror(errno)); + log_errorf("Could not chmod socket: %s", strerror(errno)); } } return fd; @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) { socket_path = SEATD_DEFAULTPATH; struct stat st; if (stat(socket_path, &st) == 0) { - log_info("removing leftover seatd socket"); + log_info("Removing leftover seatd socket"); unlink(socket_path); } } @@ -135,13 +135,13 @@ int main(int argc, char *argv[]) { int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { - log_errorf("could not create server socket: %s", strerror(errno)); + log_errorf("Could not create server socket: %s", strerror(errno)); server_finish(&server); return 1; } if (poller_add_fd(&server.poller, socket_fd, EVENT_READABLE, server_handle_connection, &server) == NULL) { - log_errorf("could not add socket to poller: %s", strerror(errno)); + log_errorf("Could not add socket to poller: %s", strerror(errno)); close(socket_fd); server_finish(&server); return 1; @@ -151,7 +151,7 @@ int main(int argc, char *argv[]) { while (server.running) { if (poller_poll(&server.poller) == -1) { - log_errorf("poller failed: %s", strerror(errno)); + log_errorf("Poller failed: %s", strerror(errno)); return 1; } } diff --git a/seatd/server.c b/seatd/server.c index 3ca73b3..37235bc 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -111,11 +111,11 @@ static int server_handle_kill(int signal, void *data) { static int set_nonblock(int fd) { int flags; if ((flags = fcntl(fd, F_GETFD)) == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - log_errorf("could not set FD_CLOEXEC on socket: %s", strerror(errno)); + log_errorf("Could not set FD_CLOEXEC on socket: %s", strerror(errno)); return -1; } if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - log_errorf("could not set O_NONBLOCK on socket: %s", strerror(errno)); + log_errorf("Could not set O_NONBLOCK on socket: %s", strerror(errno)); return -1; } return 0; @@ -124,7 +124,7 @@ 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)); + log_errorf("Could not prepare new client socket: %s", strerror(errno)); return -1; } @@ -132,11 +132,11 @@ int server_add_client(struct server *server, int fd) { client->event_source = poller_add_fd(&server->poller, fd, EVENT_READABLE, client_handle_connection, client); if (client->event_source == NULL) { - log_errorf("could not add client socket to poller: %s", strerror(errno)); + log_errorf("Could not add client socket to poller: %s", strerror(errno)); client_destroy(client); return -1; } - log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, + log_infof("New client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, client->gid); return 0; } @@ -146,14 +146,14 @@ 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 recieved an error: %s", strerror(errno)); + log_errorf("Server socket recieved an error: %s", strerror(errno)); return -1; } if (mask & EVENT_READABLE) { int new_fd = accept(fd, NULL, NULL); if (fd == -1) { - log_errorf("could not accept client connection: %s", strerror(errno)); + log_errorf("Could not accept client connection: %s", strerror(errno)); return 0; } From d8ddf590faf49dec01453adc6ea238d94ba84478 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Mar 2021 00:15:03 +0100 Subject: [PATCH 079/211] log: Include debug logs in release builds --- include/log.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/log.h b/include/log.h index f5f423e..4cf5af3 100644 --- a/include/log.h +++ b/include/log.h @@ -27,15 +27,10 @@ #define log_error(str) _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s", __FILENAME__, __LINE__, str) -#ifdef DEBUG #define log_debugf(fmt, ...) \ _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) #define log_debug(str) _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s", __FILENAME__, __LINE__, str) -#else -#define log_debugf(fmt, ...) -#define log_debug(str) -#endif void log_init(void); void _logf(enum libseat_log_level level, const char *fmt, ...) ATTRIB_PRINTF(2, 3); From 951c1790fadf57e39c47f3d47451f86cca2d0889 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:22:55 +0100 Subject: [PATCH 080/211] meson: Clean up test declarations a bit --- meson.build | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/meson.build b/meson.build index 5b06e57..83c942b 100644 --- a/meson.build +++ b/meson.build @@ -186,31 +186,18 @@ if get_option('examples').enabled() ) endif -test( - 'linked_list', - executable( - 'linked_list_test', - ['common/linked_list.c', 'tests/linked_list.c'], - include_directories: [include_directories('.', 'include')], - ) -) -test( - 'poller', - executable( - 'poller_test', - ['common/linked_list.c', 'seatd/poller.c', 'tests/poller.c'], - include_directories: [include_directories('.', 'include')], - ) -) +tests = { + 'linked_list': ['common/linked_list.c'], + 'connection': ['common/connection.c'], + 'poller': ['common/linked_list.c', 'seatd/poller.c'], +} -test( - 'connection', - executable( - 'connection_test', - ['common/connection.c', 'tests/connection.c'], - include_directories: [include_directories('.', 'include')], - ) -) +foreach name, value : tests + test(name, executable( + '@0@_test'.format(name), + ['tests/@0@.c'.format(name), value], + include_directories: [include_directories('.', 'include')])) +endforeach if get_option('server').enabled() scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) From a9b20793199c038910344ff6ffc9d63c7a976fe9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:23:09 +0100 Subject: [PATCH 081/211] meson: Make summary prettier --- meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 83c942b..7f06821 100644 --- a/meson.build +++ b/meson.build @@ -232,8 +232,8 @@ if scdoc.found() endif summary({ - 'seatd': get_option('seatd').enabled() ? 1 : 0, - 'builtin': get_option('builtin').enabled() ? 1 : 0, - 'systemd': logind_provider == 'systemd' ? 1 : 0, - 'elogind': logind_provider == 'elogind' ? 1 : 0, -}) + 'seatd': get_option('seatd').enabled(), + 'builtin': get_option('builtin').enabled(), + 'systemd': logind_provider == 'systemd', + 'elogind': logind_provider == 'elogind', +}, bool_yn: true) From c53c94985ee40a102a3229d5d584104da7ecaba6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:26:06 +0100 Subject: [PATCH 082/211] meson: Fix indentation --- meson.build | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 7f06821..dce4446 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,7 @@ add_project_arguments( ) if ['debugoptimized', 'release', 'minsize'].contains(get_option('buildtype')) - add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') + add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') endif # Hacks @@ -187,22 +187,22 @@ if get_option('examples').enabled() endif tests = { - 'linked_list': ['common/linked_list.c'], - 'connection': ['common/connection.c'], - 'poller': ['common/linked_list.c', 'seatd/poller.c'], + 'linked_list': ['common/linked_list.c'], + 'connection': ['common/connection.c'], + 'poller': ['common/linked_list.c', 'seatd/poller.c'], } foreach name, value : tests - test(name, executable( - '@0@_test'.format(name), - ['tests/@0@.c'.format(name), value], - include_directories: [include_directories('.', 'include')])) + test(name, executable( + '@0@_test'.format(name), + ['tests/@0@.c'.format(name), value], + include_directories: [include_directories('.', 'include')])) endforeach if get_option('server').enabled() - scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) + scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) else - scdoc = disabler() + scdoc = disabler() endif if scdoc.found() @@ -232,8 +232,8 @@ if scdoc.found() endif summary({ - 'seatd': get_option('seatd').enabled(), - 'builtin': get_option('builtin').enabled(), - 'systemd': logind_provider == 'systemd', - 'elogind': logind_provider == 'elogind', + 'seatd': get_option('seatd').enabled(), + 'builtin': get_option('builtin').enabled(), + 'systemd': logind_provider == 'systemd', + 'elogind': logind_provider == 'elogind', }, bool_yn: true) From 9492054920c5e3d9789e72fc543680da7bfa3dea Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:31:51 +0100 Subject: [PATCH 083/211] ci: Add clang-extra-tools to alpine Needed for the clang-format target. --- .builds/alpine.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 048e3ef..01db99d 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -3,6 +3,7 @@ packages: - meson - linux-headers - clang + - clang-extra-tools - clang-analyzer - scdoc sources: From e303e113345f3774188f3c0d83af124984d58902 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:32:27 +0100 Subject: [PATCH 084/211] Bump version to 0.5.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index dce4446..ff56845 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.4.0', + version: '0.5.0', license: 'MIT', meson_version: '>=0.53.0', default_options: [ From e802d381a168789a593cdf583562758c3f26f305 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:52:31 +0100 Subject: [PATCH 085/211] meson: Fix logind backend auto mode --- meson.build | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/meson.build b/meson.build index ff56845..fe9ab21 100644 --- a/meson.build +++ b/meson.build @@ -111,25 +111,25 @@ if get_option('seatd').enabled() endif logind_provider = '' -if get_option('logind').enabled() - # Check for libelogind first, as elogind may provide a libsystemd wrapper - # which can cause issues. - logind = dependency('libelogind', required: false) - add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') - if logind.found() - add_project_arguments('-DHAVE_ELOGIND=1', language: 'c') - logind_provider = 'elogind' - else - logind = dependency('libsystemd') - add_project_arguments('-DHAVE_SYSTEMD=1', language: 'c') - logind_provider = 'systemd' - endif +if not get_option('logind').disabled() + foreach logind_provider : ['elogind', 'systemd'] + logind = dependency('lib@0@'.format(logind_provider), required: false) + if logind.found() + break + endif + endforeach - private_files += [ - 'libseat/backend/logind.c', - 'common/drm.c', - ] - private_deps += logind + if logind.found() + add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') + add_project_arguments('-DHAVE_@0@=1'.format(logind_provider.to_upper()), language: 'c') + private_files += [ + 'libseat/backend/logind.c', + 'common/drm.c', + ] + private_deps += logind + elif get_option('logind').enabled() + error('logind backend was enabled but no supported logind provider was found') + endif endif if get_option('builtin').enabled() From 75cb20e89113b163d792b8a623416cb32b684c80 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:53:39 +0100 Subject: [PATCH 086/211] meson: Minor cleanup --- meson.build | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index fe9ab21..f41b621 100644 --- a/meson.build +++ b/meson.build @@ -16,11 +16,9 @@ libseat_soversion = 1 defaultpath = get_option('defaultpath') if defaultpath == '' - system = target_machine.system() - if system == 'linux' - defaultpath = '/run/seatd.sock' - else - defaultpath = '/var/run/seatd.sock' + defaultpath = '/var/run/seatd.sock' + if target_machine.system() == 'linux' + defaultpath = '/run/seatd.sock' endif endif @@ -51,6 +49,10 @@ if ['debugoptimized', 'release', 'minsize'].contains(get_option('buildtype')) add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') endif +if get_option('buildtype').startswith('debug') + add_project_arguments('-DDEBUG', language : 'c') +endif + # Hacks source_root = meson.current_source_dir().split('/') build_root = meson.build_root().split('/') @@ -74,11 +76,6 @@ foreach p : source_root i += 1 endforeach -if get_option('buildtype').startswith('debug') - add_project_arguments('-DDEBUG', language : 'c') -endif - - add_project_arguments( '-DREL_SRC_DIR="@0@"'.format(join_paths(relative_dir_parts) + '/'), language: 'c', @@ -208,12 +205,9 @@ endif if scdoc.found() sh = find_program('sh', native: true) scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) - - man_pages = ['seatd.1.scd'] - mandir = get_option('mandir') - foreach src : man_pages + foreach src : ['seatd.1.scd'] topic = src.split('.')[0] section = src.split('.')[1] output = '@0@.@1@'.format(topic, section) From 4e65e1bf471453d99577e6f5a2e72bfed73a3881 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:56:30 +0100 Subject: [PATCH 087/211] Correct minor misspellings --- README.md | 2 +- seatd/server.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a0c8e1..96c1caf 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Seat management takes care of mediating access to shared devices (graphics, inpu ### seatd -A seat management deamon, that does everything it needs to do. Nothing more, nothing less. Depends only on libc. +A seat management daemon, that does everything it needs to do. Nothing more, nothing less. Depends only on libc. ### libseat diff --git a/seatd/server.c b/seatd/server.c index 37235bc..0a08f50 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -146,7 +146,7 @@ int server_handle_connection(int fd, uint32_t mask, void *data) { if (mask & (EVENT_ERROR | EVENT_HANGUP)) { shutdown(fd, SHUT_RDWR); server->running = false; - log_errorf("Server socket recieved an error: %s", strerror(errno)); + log_errorf("Server socket received an error: %s", strerror(errno)); return -1; } From 1f457b1df8a7153963974553f5e50e68cb7c24b7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 13:31:37 +0100 Subject: [PATCH 088/211] meson: Disable examples by default --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- meson_options.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 01db99d..22dd536 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -10,7 +10,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 301e88b..b323894 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,7 +9,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build seatd + meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index e13566a..b9a9eaa 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -12,7 +12,7 @@ tasks: ninja -C build test - smoketest: | rm -rf build - meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd + meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled -Dlogind=disabled build seatd ninja -C build timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | diff --git a/meson_options.txt b/meson_options.txt index e32221a..73b9634 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,6 +2,6 @@ option('logind', type: 'feature', value: 'disabled', description: 'logind suppor option('seatd', type: 'feature', value: 'enabled', description: 'seatd support') option('builtin', type: 'feature', value: 'disabled', description: 'builtin seatd server') option('server', type: 'feature', value: 'enabled', description: 'seatd server') -option('examples', type: 'feature', value: 'enabled', description: 'libseat example programs') +option('examples', type: 'feature', value: 'disabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('defaultpath', type: 'string', value: '', description: 'Default location for seatd socket (empty for default)') From 745d66292034c53aef1febc72248bc3800826149 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 13:33:20 +0100 Subject: [PATCH 089/211] ci: Reduce test runs from 5 to 2 --- .builds/smoketest-builtin.sh | 2 +- .builds/smoketest-seatd.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.builds/smoketest-builtin.sh b/.builds/smoketest-builtin.sh index 8341466..b022b77 100755 --- a/.builds/smoketest-builtin.sh +++ b/.builds/smoketest-builtin.sh @@ -16,7 +16,7 @@ fi # Run simpletest a few times # cnt=0 -while [ "$cnt" -lt 5 ] +while [ "$cnt" -lt 2 ] do echo "Simpletest run $cnt" if ! sudo LIBSEAT_BACKEND=builtin LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index f6f9732..7c5b7fe 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -38,7 +38,7 @@ fi # Run simpletest a few times # cnt=0 -while [ "$cnt" -lt 5 ] +while [ "$cnt" -lt 2 ] do echo "Simpletest run $cnt" if ! LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file From a9865adb5f354f762a7d38c981187440ccb80a60 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 13:33:35 +0100 Subject: [PATCH 090/211] ci: Remove unnecessary env vars --- .builds/smoketest-builtin.sh | 4 ++-- .builds/smoketest-seatd.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/smoketest-builtin.sh b/.builds/smoketest-builtin.sh index b022b77..332c3f9 100755 --- a/.builds/smoketest-builtin.sh +++ b/.builds/smoketest-builtin.sh @@ -18,8 +18,8 @@ fi cnt=0 while [ "$cnt" -lt 2 ] do - echo "Simpletest run $cnt" - if ! sudo LIBSEAT_BACKEND=builtin LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file + echo "Simpletest run $((cnt+1))" + if ! sudo LIBSEAT_BACKEND=builtin ./build/simpletest $file then echo "Simpletest failed" exit $res diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index 7c5b7fe..d8c2ac3 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -40,8 +40,8 @@ fi cnt=0 while [ "$cnt" -lt 2 ] do - echo "Simpletest run $cnt" - if ! LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file + echo "Simpletest run $((cnt+1))" + if ! SEATD_SOCK=./seatd.sock ./build/simpletest $file then echo "Simpletest failed" sudo killall seatd From 34f55a3e2479daf0dae294dd22af25fcb6b25a01 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 14:27:45 +0100 Subject: [PATCH 091/211] contrib: Add Documentation to systemd unit --- contrib/systemd/seatd.service | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/systemd/seatd.service b/contrib/systemd/seatd.service index 2751217..a450058 100644 --- a/contrib/systemd/seatd.service +++ b/contrib/systemd/seatd.service @@ -1,5 +1,6 @@ [Unit] Description=Seat management daemon +Documentation=man:seatd(1) [Service] Type=simple From 0d855a28f20ab3d7b2058fbe58a172a97affbde5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 18 Mar 2021 15:45:26 +0100 Subject: [PATCH 092/211] readme: Remove alpha label --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96c1caf..8291279 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A minimal seat management daemon, and a universal seat management library. -Currently supports Linux and FreeBSD. Alpha +Currently supports Linux and FreeBSD. ## What is seat management? From 5ad91ae9dad205331ede6579b2b24b53e02a6287 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 21 Mar 2021 13:44:57 +0100 Subject: [PATCH 093/211] client: enable cr_pid on FreeBSD >= 12.3 https://cgit.freebsd.org/src/commit/?id=925f44f33862908f9a2e72520a17af148c7d0db5 https://cgit.freebsd.org/src/commit/?id=2b61bda2c75f30f6eadd18fb891fd885e4c8d19d --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index d0f321d..1bfe94a 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -40,7 +40,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) == -1) { return -1; } -#if __FreeBSD_version >= 1300030 +#if __FreeBSD_version >= 1300030 || (__FreeBSD_version >= 1202506 && __FreeBSD_version < 1300000) *pid = cred.cr_pid; #else *pid = -1; From 9a7824b7c3ff5c957632671e91454fc84fbcdda8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Mar 2021 10:05:12 +0100 Subject: [PATCH 094/211] Add no-op session This is useful for headless testing, for instance with VKMS: modprobe vkms export WLR_DRM_DEVICES=/dev/dri/card1 export WLR_BACKENDS=drm export LIBSEAT_BACKEND=noop sway We don't need any of the VT handling in this case. --- include/libseat.h | 2 + libseat/backend/noop.c | 135 +++++++++++++++++++++++++++++++++++++++++ libseat/libseat.c | 5 ++ meson.build | 2 +- 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 libseat/backend/noop.c diff --git a/include/libseat.h b/include/libseat.h index 5375cd6..82098ea 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -1,6 +1,8 @@ #ifndef _LIBSEAT_H #define _LIBSEAT_H +#include + /* * An opaque struct containing an opened seat, created by libseat_open_seat and * destroyed by libseat_close_seat. diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c new file mode 100644 index 0000000..71d0224 --- /dev/null +++ b/libseat/backend/noop.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backend.h" +#include "log.h" + +struct backend_noop { + struct libseat base; + struct libseat_seat_listener *seat_listener; + void *seat_listener_data; + + bool initial_setup; + int sockets[2]; +}; + +extern const struct seat_impl noop_impl; + +static struct backend_noop *backend_noop_from_libseat_backend(struct libseat *base) { + assert(base->impl == &noop_impl); + return (struct backend_noop *)base; +} + +static void destroy(struct backend_noop *backend) { + close(backend->sockets[0]); + close(backend->sockets[1]); + free(backend); +} + +static int close_seat(struct libseat *base) { + struct backend_noop *backend = backend_noop_from_libseat_backend(base); + destroy(backend); + return 0; +} + +static int disable_seat(struct libseat *base) { + (void)base; + return 0; +} + +static const char *seat_name(struct libseat *base) { + (void)base; + return "noop"; +} + +static int open_device(struct libseat *base, const char *path, int *fd) { + (void)base; + + int tmpfd = open(path, O_RDWR | O_CLOEXEC); + if (tmpfd < 0) { + log_errorf("Failed to open device: %s", strerror(errno)); + return -1; + } + + *fd = tmpfd; + return tmpfd; +} + +static int close_device(struct libseat *base, int device_id) { + (void)base; + (void)device_id; + return 0; +} + +static int switch_session(struct libseat *base, int s) { + (void)base; + (void)s; + log_errorf("No-op backend cannot switch to session %d", s); + return -1; +} + +static int get_fd(struct libseat *base) { + struct backend_noop *backend = backend_noop_from_libseat_backend(base); + return backend->sockets[0]; +} + +static int dispatch_background(struct libseat *base, int timeout) { + struct backend_noop *backend = backend_noop_from_libseat_backend(base); + + if (backend->initial_setup) { + backend->initial_setup = false; + backend->seat_listener->enable_seat(&backend->base, backend->seat_listener_data); + } + + struct pollfd fd = { + .fd = backend->sockets[0], + .events = POLLIN, + }; + if (poll(&fd, 1, timeout) < 0) { + if (errno == EAGAIN || errno == EINTR) { + return 0; + } else { + return -1; + } + } + + return 0; +} + +static struct libseat *noop_open_seat(struct libseat_seat_listener *listener, void *data) { + struct backend_noop *backend = calloc(1, sizeof(struct backend_noop)); + if (backend == NULL) { + return NULL; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, backend->sockets) != 0) { + log_errorf("socketpair() failed: %s", strerror(errno)); + free(backend); + return NULL; + } + + backend->seat_listener = listener; + backend->seat_listener_data = data; + backend->base.impl = &noop_impl; + + return &backend->base; +} + +const struct seat_impl noop_impl = { + .open_seat = noop_open_seat, + .disable_seat = disable_seat, + .close_seat = close_seat, + .seat_name = seat_name, + .open_device = open_device, + .close_device = close_device, + .switch_session = switch_session, + .get_fd = get_fd, + .dispatch = dispatch_background, +}; diff --git a/libseat/libseat.c b/libseat/libseat.c index b1e8bb2..a7e079c 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -13,6 +13,7 @@ extern const struct seat_impl seatd_impl; extern const struct seat_impl logind_impl; extern const struct seat_impl builtin_impl; +extern const struct seat_impl noop_impl; static const struct named_backend impls[] = { #ifdef SEATD_ENABLED @@ -24,6 +25,7 @@ static const struct named_backend impls[] = { #ifdef BUILTIN_ENABLED {"builtin", &builtin_impl}, #endif + {"noop", &noop_impl}, {NULL, NULL}, }; @@ -62,6 +64,9 @@ struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void * struct libseat *backend = NULL; for (const struct named_backend *iter = impls; iter->backend != NULL; iter++) { + if (iter->backend == &noop_impl) { + continue; + } backend = iter->backend->open_seat(listener, data); if (backend != NULL) { log_infof("Seat opened with backend '%s'", iter->name); diff --git a/meson.build b/meson.build index f41b621..c3800ae 100644 --- a/meson.build +++ b/meson.build @@ -145,7 +145,7 @@ symbols_file = 'libseat/libseat.syms' symbols_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), symbols_file) lib = library( 'seat', # This results in the library being called 'libseat' - [ 'libseat/libseat.c' ], + [ 'libseat/libseat.c', 'libseat/backend/noop.c' ], soversion: libseat_soversion, link_with: private_lib, include_directories: [include_directories('.', 'include')], From fa2700126fe355939744a5e77159e7fc4a631575 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Mar 2021 10:07:00 +0100 Subject: [PATCH 095/211] meson: declare libseat dependency This can be used by parent projects when seatd is a subproject: libseat = dependency('libseat', fallback: ['seatd', 'libseat']) --- meson.build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meson.build b/meson.build index c3800ae..482f877 100644 --- a/meson.build +++ b/meson.build @@ -164,6 +164,12 @@ pkgconfig.generate(lib, description: 'Seat management library', ) +libseat = declare_dependency( + link_with: lib, + dependencies: private_deps, + include_directories: include_directories('include', is_system: true), +) + if get_option('server').enabled() executable( 'seatd', From f9ba8b57bc6505964d8055c87428234eb20f7992 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 26 Mar 2021 11:32:23 +0100 Subject: [PATCH 096/211] Avoid a clang-format quirk clang-format wants to put the terminating NULLs on the same line as the noop backend when it doens't have any immediate non-NULL neighbors. Add a newline to stop it. --- libseat/libseat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libseat/libseat.c b/libseat/libseat.c index a7e079c..42449a8 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -26,6 +26,7 @@ static const struct named_backend impls[] = { {"builtin", &builtin_impl}, #endif {"noop", &noop_impl}, + {NULL, NULL}, }; From 50da164ddcf925225f360ae2178a3d72961bbc8a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 8 Apr 2021 23:07:04 +0200 Subject: [PATCH 097/211] ci: Use 'auto' for arch linux logind --- .builds/archlinux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index b323894..27391f0 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,7 +9,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd + meson -Db_sanitize=address -Dlogind=auto -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | From 3ce4c5781462a06bb08458e73df39840f9e2f731 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 8 Apr 2021 23:00:13 +0200 Subject: [PATCH 098/211] meson: make 'logind' var always available --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 482f877..beb121c 100644 --- a/meson.build +++ b/meson.build @@ -107,6 +107,7 @@ if get_option('seatd').enabled() add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif +logind = disabler() logind_provider = '' if not get_option('logind').disabled() foreach logind_provider : ['elogind', 'systemd'] From 385cc0039db13448856f4241b05d46533dc98b16 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 13:24:19 +0200 Subject: [PATCH 099/211] build: add explicit logind provider option, auto-detect by default Allow package maintainers to explicitly select a logind provider by passing -Dlogind=systemd or -Dlogind=elogind. In case both are available (e.g. for distributions which support both), this makes it possible to gte deterministic behavior. By default, auto-detect the logind provider. That way, users which have systemd or elogind installed get the backend built by default. --- meson.build | 22 +++++++++++++--------- meson_options.txt | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index beb121c..5454053 100644 --- a/meson.build +++ b/meson.build @@ -109,13 +109,19 @@ endif logind = disabler() logind_provider = '' -if not get_option('logind').disabled() - foreach logind_provider : ['elogind', 'systemd'] - logind = dependency('lib@0@'.format(logind_provider), required: false) - if logind.found() - break - endif - endforeach +if get_option('logind') != 'disabled' + if get_option('logind') == 'auto' + assert(get_option('auto_features').auto(), '-Dlogind 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 + else + logind_provider = get_option('logind') + logind = dependency('lib@0@'.format(logind_provider)) + endif if logind.found() add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') @@ -125,8 +131,6 @@ if not get_option('logind').disabled() 'common/drm.c', ] private_deps += logind - elif get_option('logind').enabled() - error('logind backend was enabled but no supported logind provider was found') endif endif diff --git a/meson_options.txt b/meson_options.txt index 73b9634..9c36fa3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,4 @@ -option('logind', type: 'feature', value: 'disabled', description: 'logind support') +option('logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support') option('seatd', type: 'feature', value: 'enabled', description: 'seatd support') option('builtin', type: 'feature', value: 'disabled', description: 'builtin seatd server') option('server', type: 'feature', value: 'enabled', description: 'seatd server') From 392da918e626641edb337d0afd9c0d72695babed Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 13:30:18 +0200 Subject: [PATCH 100/211] build: fix logind feature summary when auto-detected If -Dlogind=auto but systemd/elogind isn't available, logind_provider would get set to the last item of the foreach loop. This would incorrectly report "systemd: YES". --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 5454053..8f7efb2 100644 --- a/meson.build +++ b/meson.build @@ -239,6 +239,6 @@ endif summary({ 'seatd': get_option('seatd').enabled(), 'builtin': get_option('builtin').enabled(), - 'systemd': logind_provider == 'systemd', - 'elogind': logind_provider == 'elogind', + 'systemd': logind.found() and logind_provider == 'systemd', + 'elogind': logind.found() and logind_provider == 'elogind', }, bool_yn: true) From ee409138109c5f53310f0d81d2b591157b39d622 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 13:36:41 +0200 Subject: [PATCH 101/211] build: don't explicitly search for sh This removes the "Program sh found" line in the build logs, and should not change anything else. --- meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 8f7efb2..60c96f0 100644 --- a/meson.build +++ b/meson.build @@ -214,7 +214,6 @@ else endif if scdoc.found() - sh = find_program('sh', native: true) scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) mandir = get_option('mandir') @@ -228,7 +227,7 @@ if scdoc.found() input: 'man/' + src, output: output, command: [ - sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) + 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) From 753c5276cf800ae1fb1c7747bfcdaeff5e45d6de Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 14:30:04 +0200 Subject: [PATCH 102/211] build: don't allow "auto" for seatd, builtin, server and examples These features don't have any dependencies, so "auto" doesn't make sense. --- meson.build | 19 ++++++++++++------- meson_options.txt | 8 ++++---- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 60c96f0..722735a 100644 --- a/meson.build +++ b/meson.build @@ -102,7 +102,11 @@ server_files = [ 'seatd/server.c', ] -if get_option('seatd').enabled() +with_seatd = get_option('seatd') == 'enabled' +with_builtin = get_option('builtin') == 'enabled' +with_server = get_option('server') == 'enabled' + +if with_seatd private_files += 'libseat/backend/seatd.c' add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif @@ -134,7 +138,7 @@ if get_option('logind') != 'disabled' endif endif -if get_option('builtin').enabled() +if with_builtin add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c') private_files += server_files endif @@ -175,7 +179,7 @@ libseat = declare_dependency( include_directories: include_directories('include', is_system: true), ) -if get_option('server').enabled() +if with_server executable( 'seatd', [ server_files, 'seatd/seatd.c' ], @@ -184,7 +188,7 @@ if get_option('server').enabled() ) endif -if get_option('examples').enabled() +if get_option('examples') == 'enabled' executable( 'simpletest', ['examples/simpletest/main.c'], @@ -207,7 +211,7 @@ foreach name, value : tests include_directories: [include_directories('.', 'include')])) endforeach -if get_option('server').enabled() +if with_server scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) else scdoc = disabler() @@ -236,8 +240,9 @@ if scdoc.found() endif summary({ - 'seatd': get_option('seatd').enabled(), - 'builtin': get_option('builtin').enabled(), + 'seatd': with_seatd, + 'builtin': with_builtin, + 'server': with_server, 'systemd': logind.found() and logind_provider == 'systemd', 'elogind': logind.found() and logind_provider == 'elogind', }, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt index 9c36fa3..144ce7a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option('logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support') -option('seatd', type: 'feature', value: 'enabled', description: 'seatd support') -option('builtin', type: 'feature', value: 'disabled', description: 'builtin seatd server') -option('server', type: 'feature', value: 'enabled', description: 'seatd server') -option('examples', type: 'feature', value: 'disabled', description: 'libseat example programs') +option('seatd', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd support') +option('builtin', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'builtin seatd server') +option('server', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd server') +option('examples', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('defaultpath', type: 'string', value: '', description: 'Default location for seatd socket (empty for default)') From 5884a6003ab77109050df11af0c06956257df910 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 10 Apr 2021 09:05:05 +0200 Subject: [PATCH 103/211] build: disable logind on -Dauto_features=disabled -Dlogind=auto Setting auto_features=disabled is supposed to disable all optional dependencies. Since we aren't using a feature option here, we need to manually add logic to disable logind in this case. --- meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 722735a..a7e4734 100644 --- a/meson.build +++ b/meson.build @@ -114,7 +114,9 @@ endif logind = disabler() logind_provider = '' if get_option('logind') != 'disabled' - if get_option('logind') == 'auto' + if get_option('logind') == 'auto' and get_option('auto_features').disabled() + # Disable logind + elif get_option('logind') == 'auto' assert(get_option('auto_features').auto(), '-Dlogind 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) From 81ff0a09a93303233057f217aaa3f679db3bbe5c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 10 Apr 2021 09:15:47 +0200 Subject: [PATCH 104/211] build: set pkgconfig/dependency variables for features This allows libseat users to e.g. advise people to chmod a+s the executable if libseat is built with the builtin backend. While bumping the Meson version, adjust the scdoc logic to avoid the following warnings: WARNING: Project targeting '>=0.56.0' but tried to use feature deprecated since '0.56.0': Dependency.get_pkgconfig_variable. use Dependency.get_variable(pkgconfig : ...) instead WARNING: Project targeting '>=0.56.0' but tried to use feature deprecated since '0.55.0': ExternalProgram.path. use ExternalProgram.full_path() instead --- meson.build | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index a7e4734..7a70cb6 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '0.5.0', license: 'MIT', - meson_version: '>=0.53.0', + meson_version: '>=0.56.0', default_options: [ 'c_std=c11', 'warning_level=3', @@ -167,18 +167,26 @@ lib = library( install_headers('include/libseat.h') +libseat_vars = { + 'have_seatd': with_seatd.to_string(), + 'have_logind': logind.found().to_string(), + 'have_builtin': with_builtin.to_string(), +} + pkgconfig = import('pkgconfig') pkgconfig.generate(lib, version: meson.project_version(), filebase: 'libseat', name: 'libseat', description: 'Seat management library', + variables: libseat_vars, ) libseat = declare_dependency( link_with: lib, dependencies: private_deps, include_directories: include_directories('include', is_system: true), + variables: libseat_vars, ) if with_server @@ -220,7 +228,7 @@ else endif if scdoc.found() - scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) + scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) mandir = get_option('mandir') foreach src : ['seatd.1.scd'] @@ -233,7 +241,7 @@ if scdoc.found() input: 'man/' + src, output: output, command: [ - 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) + 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.full_path(), output) ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) From 5535c2c3b19b42ebfe4c451600059e9418e401a6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 17 Apr 2021 17:08:51 +0200 Subject: [PATCH 105/211] contrib/systemd: Use a different group "video" was used for convenience in the example, but a dedicated group is preferable so that a user does not gain the ability to bypass the seat manager and open devices directly. --- contrib/systemd/seatd.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/systemd/seatd.service b/contrib/systemd/seatd.service index a450058..bbbaf23 100644 --- a/contrib/systemd/seatd.service +++ b/contrib/systemd/seatd.service @@ -4,7 +4,8 @@ Documentation=man:seatd(1) [Service] Type=simple -ExecStart=seatd -g video +# Specify the group you'd like to grant access to seatd +ExecStart=seatd -g seat Restart=always RestartSec=1 From 36f54adc2c1b16943e5470af3ad85d2b4cdf480c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 23 Apr 2021 14:13:58 +0000 Subject: [PATCH 106/211] libseat/seatd: downgrade ENOENT log to info The socket is expected not to be found if seatd is not running. In general other backends will be attempted after seatd. There is already an error message in case no backend can be started. --- libseat/backend/seatd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 2dea3ca..07026ba 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -75,7 +75,11 @@ static int seatd_connect(void) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (connect(fd, &addr.generic, size) == -1) { - log_errorf("Could not connect to socket %s: %s", path, strerror(errno)); + if (errno == ENOENT) { + log_infof("Could not connect to socket %s: %s", path, strerror(errno)); + } else { + log_errorf("Could not connect to socket %s: %s", path, strerror(errno)); + } close(fd); return -1; }; From 355cc9c944a29d29736de84e782a2e91168f1a59 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 25 Apr 2021 20:16:19 +0200 Subject: [PATCH 107/211] meson: Support building builtin without seatd The builtin backend relies on the seatd backend implementation. When builtin was enabled without seatd, compilation would fail due to the implementation not being included. Include the implementation if either seatd or builtin is enabled. --- meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 7a70cb6..6299f4e 100644 --- a/meson.build +++ b/meson.build @@ -106,8 +106,11 @@ with_seatd = get_option('seatd') == 'enabled' with_builtin = get_option('builtin') == 'enabled' with_server = get_option('server') == 'enabled' -if with_seatd +if with_seatd or with_builtin private_files += 'libseat/backend/seatd.c' +endif + +if with_seatd add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif From fc97206df9b8fbba09de8b320fab6f75235a5c7f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 19 May 2021 17:48:12 +0200 Subject: [PATCH 108/211] readme: Update discuss section --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8291279..9aa9e99 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,6 @@ Why spend time isolating logind and keeping up with upstream when we could inste Instead of giving user shell developers more work, libseat aims to make supporting seatd less work than what they're currently implementing. This is done by taking care of all the seat management needs with multiple backends, providing not only seatd support, but replacing the existing logind and direct seat management implementations. -## I want more +## How to discuss -Go to #kennylevinsen @ chat.freenode.net to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). +Go to #kennylevinsen @ irc.libera.chat to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). From bff09d88594a35d343b16b21b75495c4284f1292 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Sun, 20 Jun 2021 22:28:33 +0200 Subject: [PATCH 109/211] link with rt Since seatd uses `clock_gettime`, this is needed when cross-compiling. This came up in https://github.com/JuliaPackaging/Yggdrasil/pull/3193. --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 6299f4e..89fa8df 100644 --- a/meson.build +++ b/meson.build @@ -143,6 +143,10 @@ if get_option('logind') != 'disabled' endif endif +# needed for cross-compilation +realtime = meson.get_compiler('c').find_library('rt') +private_deps += realtime + if with_builtin add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c') private_files += server_files @@ -198,6 +202,7 @@ if with_server [ server_files, 'seatd/seatd.c' ], include_directories: [include_directories('.', 'include')], install: true, + dependencies: [realtime], ) endif From 2204db5531ed16bf32f969645e7177f6118f8a8e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 23 Jun 2021 08:08:33 +0000 Subject: [PATCH 110/211] build: add prefix to libseat options The option names are a little bit confusing, because it's not clear which ones toggle libseat features, and which ones toggle seatd features. Add a "libseat-" prefix to libseat-specific features, to make it more obvious that they only are about the library. --- meson.build | 22 +++++++++++----------- meson_options.txt | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 89fa8df..9d48706 100644 --- a/meson.build +++ b/meson.build @@ -102,8 +102,8 @@ server_files = [ 'seatd/server.c', ] -with_seatd = get_option('seatd') == 'enabled' -with_builtin = get_option('builtin') == 'enabled' +with_seatd = get_option('libseat-seatd') == 'enabled' +with_builtin = get_option('libseat-builtin') == 'enabled' with_server = get_option('server') == 'enabled' if with_seatd or with_builtin @@ -116,11 +116,11 @@ endif logind = disabler() logind_provider = '' -if get_option('logind') != 'disabled' - if get_option('logind') == 'auto' and get_option('auto_features').disabled() +if get_option('libseat-logind') != 'disabled' + if get_option('libseat-logind') == 'auto' and get_option('auto_features').disabled() # Disable logind - elif get_option('logind') == 'auto' - assert(get_option('auto_features').auto(), '-Dlogind must be set to systemd or elogind since auto_features != auto') + 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() @@ -128,7 +128,7 @@ if get_option('logind') != 'disabled' endif endforeach else - logind_provider = get_option('logind') + logind_provider = get_option('libseat-logind') logind = dependency('lib@0@'.format(logind_provider)) endif @@ -258,9 +258,9 @@ if scdoc.found() endif summary({ - 'seatd': with_seatd, - 'builtin': with_builtin, + 'libseat-seatd': with_seatd, + 'libseat-builtin': with_builtin, + 'libseat-systemd': logind.found() and logind_provider == 'systemd', + 'libseat-elogind': logind.found() and logind_provider == 'elogind', 'server': with_server, - 'systemd': logind.found() and logind_provider == 'systemd', - 'elogind': logind.found() and logind_provider == 'elogind', }, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt index 144ce7a..0731ac4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,6 +1,6 @@ -option('logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support') -option('seatd', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd support') -option('builtin', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'builtin seatd server') +option('libseat-logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support for libseat') +option('libseat-seatd', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd support for libseat') +option('libseat-builtin', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'built-in seatd server for libseat') option('server', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd server') option('examples', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') From 7a6d12ff7a4e3e19d6c7c9e0f2d270491168e785 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 8 Jul 2021 23:41:09 +0200 Subject: [PATCH 111/211] libseat/seatd: Return executed events Dispatch needs to report if something has happened, which includes events executed from the queue as these could have lead to additional dispatch and queuing. --- libseat/backend/seatd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 07026ba..9bc5e6e 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -206,10 +206,11 @@ static int queue_event(struct backend_seatd *backend, int opcode) { return 0; } -static void execute_events(struct backend_seatd *backend) { +static int execute_events(struct backend_seatd *backend) { struct linked_list list; linked_list_init(&list); linked_list_take(&list, &backend->pending_events); + int executed = 0; while (!linked_list_empty(&list)) { struct pending_event *ev = (struct pending_event *)list.next; int opcode = ev->opcode; @@ -231,7 +232,9 @@ static void execute_events(struct backend_seatd *backend) { log_errorf("Invalid opcode: %d", opcode); abort(); } + executed++; } + return executed; } static int dispatch_pending(struct backend_seatd *backend, int *opcode) { @@ -341,7 +344,7 @@ static int dispatch_background(struct libseat *base, int timeout) { return -1; } - execute_events(backend); + dispatched += execute_events(backend); return dispatched; } From 5923e0edc9bb157cf6398b63d51cc3c0aaf06001 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 9 Jul 2021 00:09:14 +0200 Subject: [PATCH 112/211] libseat/seatd: Add dispatch_pending_and_execute This handler returns the number of dispatched or executed events, or -1 if dispatch_pending failed. This helper is used to clean up dispatch_background, which now ensures that all events are executed before we read or poll the connection, and have improved error handling in the corner case where the second dispatch_pending failed. --- libseat/backend/seatd.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 9bc5e6e..3600b50 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -262,6 +262,15 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) { return packets; } +static int dispatch_pending_and_execute(struct backend_seatd *backend) { + int dispatched = dispatch_pending(backend, NULL); + if (dispatched == -1) { + return -1; + } + dispatched += execute_events(backend); + return dispatched; +} + static int poll_connection(struct backend_seatd *backend, int timeout) { struct pollfd fd = { .fd = backend->connection.fd, @@ -324,28 +333,34 @@ static int dispatch_background(struct libseat *base, int timeout) { return -1; } - int dispatched = dispatch_pending(backend, NULL); - if (dispatched > 0) { - // We don't want to block if we dispatched something, as the - // caller might be waiting for the result. However, we'd also - // like to read anything pending. - timeout = 0; + int predispatch = dispatch_pending_and_execute(backend); + if (predispatch == -1) { + return -1; } + + // We don't want to block if we dispatched something, as the + // caller might be waiting for the result. However, we'd also + // like to read anything pending. int read = 0; - if (timeout == 0) { + if (predispatch == 0 || timeout == 0) { read = connection_read(&backend->connection); } else { read = poll_connection(backend, timeout); } - if (read > 0) { - dispatched += dispatch_pending(backend, NULL); + + if (read == 0) { + return predispatch; } else if (read == -1 && errno != EAGAIN) { log_errorf("Could not read from connection: %s", strerror(errno)); return -1; } - dispatched += execute_events(backend); - return dispatched; + int postdispatch = dispatch_pending_and_execute(backend); + if (postdispatch == -1) { + return -1; + } + + return predispatch + postdispatch; } static struct libseat *_open_seat(struct libseat_seat_listener *listener, void *data, int fd) { From 6444da60930fbe92b8c7e868372c90887853e60b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 9 Jul 2021 00:16:10 +0200 Subject: [PATCH 113/211] libseat: Rename dispatch_background in backends This name never made much sense. dispatch_and_execute is more meaningful, especially when compared to the non-executing dispatch function. --- libseat/backend/logind.c | 4 ++-- libseat/backend/seatd.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index c6f2aaf..aa659a6 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -213,7 +213,7 @@ static int poll_connection(struct backend_logind *backend, int timeout) { return 0; } -static int dispatch_background(struct libseat *base, int timeout) { +static int dispatch_and_execute(struct libseat *base, int timeout) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); if (backend->initial_setup) { backend->initial_setup = false; @@ -688,5 +688,5 @@ const struct seat_impl logind_impl = { .close_device = close_device, .switch_session = switch_session, .get_fd = get_fd, - .dispatch = dispatch_background, + .dispatch = dispatch_and_execute, }; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 3600b50..96b4681 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -326,7 +326,7 @@ static int get_fd(struct libseat *base) { return backend->connection.fd; } -static int dispatch_background(struct libseat *base, int timeout) { +static int dispatch_and_execute(struct libseat *base, int timeout) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); if (backend->error) { errno = ENOTCONN; @@ -575,7 +575,7 @@ const struct seat_impl seatd_impl = { .close_device = close_device, .switch_session = switch_session, .get_fd = get_fd, - .dispatch = dispatch_background, + .dispatch = dispatch_and_execute, }; #ifdef BUILTIN_ENABLED @@ -660,6 +660,6 @@ const struct seat_impl builtin_impl = { .close_device = close_device, .switch_session = switch_session, .get_fd = get_fd, - .dispatch = dispatch_background, + .dispatch = dispatch_and_execute, }; #endif From d03e9d1c35b491851c7097dd7b42faa02c9ff96f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 01:09:57 +0200 Subject: [PATCH 114/211] seatd: We shouldn't poll if predispatch > 0 This condition was accidentally botched as part of 5923e0edc9bb157cf6398b63d51cc3c0aaf06001 --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 96b4681..97971aa 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -342,7 +342,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { // caller might be waiting for the result. However, we'd also // like to read anything pending. int read = 0; - if (predispatch == 0 || timeout == 0) { + if (predispatch > 0 || timeout == 0) { read = connection_read(&backend->connection); } else { read = poll_connection(backend, timeout); From 312d6906aef9c9ae7aba62f0ad60c83bb5f95b00 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 20 Apr 2021 22:54:30 +0200 Subject: [PATCH 115/211] seatd: s6-style readiness notification support This adds the ability to specify the number of an fd that is inherited by the process as open. Once seatd is read to serve requests, it will write a single newline and close the fd. --- man/seatd.1.scd | 5 +++++ seatd/seatd.c | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index ab79ee1..5945782 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -13,6 +13,11 @@ seatd - A seat management daemon *-h* Show help message and quit. +*-n* + FD to notify readiness on. A single newline will be written and the fd + closed when seatd is ready to serve requests. This is compatible with + s6's notification protocol. + *-u * User to own the seatd socket. diff --git a/seatd/seatd.c b/seatd/seatd.c index 278f857..420847d 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -70,6 +70,7 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd [options]\n" "\n" " -h Show this help message\n" + " -n FD to notify readiness on\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" @@ -78,9 +79,17 @@ int main(int argc, char *argv[]) { int c; int uid = 0, gid = 0; + int readiness = -1; const char *socket_path = getenv("SEATD_SOCK"); - while ((c = getopt(argc, argv, "vhs:g:u:")) != -1) { + while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { switch (c) { + case 'n': + readiness = atoi(optarg); + if (readiness < 0) { + fprintf(stderr, "Invalid readiness fd: %s\n", optarg); + return 1; + } + break; case 's': socket_path = optarg; break; @@ -149,6 +158,13 @@ int main(int argc, char *argv[]) { log_info("seatd started"); + if (readiness != -1) { + if (write(readiness, "\n", 1) == -1) { + log_errorf("Could not write readiness signal: %s\n", strerror(errno)); + } + close(readiness); + } + while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("Poller failed: %s", strerror(errno)); From c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 00:45:25 +0200 Subject: [PATCH 116/211] seatd: Only set UID/GID when specified The UID/GID defaulted to 0, which results in trying to chown to root when a UID or GID isn't requested. Instead, deafult to -1 so that the unspecified values are left intact. --- seatd/seatd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 420847d..826b994 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -41,11 +41,11 @@ static int open_socket(const char *path, int uid, int gid) { close(fd); return -1; } - if (uid != 0 || gid != 0) { - if (chown(path, uid, gid) == -1) { + if (uid != -1 || gid != -1) { + if (fchown(fd, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); - } else if (chmod(path, 0770) == -1) { + } else if (fchmod(fd, 0770) == -1) { log_errorf("Could not chmod socket: %s", strerror(errno)); } } @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { "\n"; int c; - int uid = 0, gid = 0; + 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) { From 1e98727ae9dfdb23316249a4f32b3169d956e417 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 00:06:44 +0200 Subject: [PATCH 117/211] seatd-launch: Add seatd launch wrapper This launch wrapper is used to conveniently start a new seatd instance, wait for it to be ready, and launch a target application. --- meson.build | 7 ++ seatd-launch/seatd-launch.c | 123 ++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 seatd-launch/seatd-launch.c diff --git a/meson.build b/meson.build index 9d48706..1131b4b 100644 --- a/meson.build +++ b/meson.build @@ -204,6 +204,13 @@ if with_server install: true, dependencies: [realtime], ) + executable( + 'seatd-launch', + [ 'seatd-launch/seatd-launch.c' ], + include_directories: [include_directories('.', 'include')], + install: true, + dependencies: [realtime], + ) endif if get_option('examples') == 'enabled' diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c new file mode 100644 index 0000000..ffa6cc6 --- /dev/null +++ b/seatd-launch/seatd-launch.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + (void)argc; + char sockbuf[256]; + + sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); + unlink(sockbuf); + + int fds[2]; + if (pipe(fds) == -1) { + perror("Could not create pipe"); + goto error; + } + + 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]); + + char pipebuf[8]; + sprintf(pipebuf, "%d", fds[1]); + struct passwd *user = getpwuid(getuid()); + + // TODO: Make seatd accept the numeric UID + execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); + perror("Could not start seatd"); + goto error; + } + close(fds[1]); + + // Drop privileges + if (setgid(getgid()) == -1) { + perror("Could not set gid to drop privileges"); + goto error_seatd; + } + if (setuid(getuid()) == -1) { + perror("Could not set uid to drop privileges"); + goto error_seatd; + } + + char buf[1] = {0}; + while (true) { + pid_t p = waitpid(seatd_child, NULL, WNOHANG); + if (p == seatd_child) { + fprintf(stderr, "seatd exited prematurely\n"); + goto error_seatd; + } else if (p == -1 && (errno != EINTR && errno != ECHILD)) { + perror("Could not wait for seatd process"); + goto error_seatd; + } + + struct pollfd fd = { + .fd = fds[0], + .events = POLLIN, + }; + + // We poll with timeout to avoid a racing on a blocking read + if (poll(&fd, 1, 1000) == -1) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + perror("Could not poll notification fd"); + goto error_seatd; + } + } + + if (fd.revents & POLLIN) { + ssize_t n = read(fds[0], buf, 1); + if (n == -1 && errno != EINTR) { + perror("Could not read from pipe"); + goto error_seatd; + } else if (n > 0) { + break; + } + } + } + close(fds[0]); + + pid_t child = fork(); + if (child == -1) { + perror("Could not fork target process"); + goto error_seatd; + } else if (child == 0) { + setenv("SEATD_SOCK", sockbuf, 1); + execv(argv[1], &argv[1]); + perror("Could not start target"); + goto error_seatd; + } + + while (true) { + pid_t p = waitpid(child, NULL, 0); + if (p == child) { + break; + } else if (p == -1 && errno != EINTR) { + perror("Could not wait for target process"); + goto error_seatd; + } + } + + unlink(sockbuf); + kill(seatd_child, SIGTERM); + return 0; + +error_seatd: + unlink(sockbuf); + kill(seatd_child, SIGTERM); +error: + return 1; +} From 978dec42b052ae56f55fe4ea8a2554e5611ec0fa Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 00:46:49 +0200 Subject: [PATCH 118/211] ci: Use seatd-launch --- .builds/smoketest-seatd.sh | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index d8c2ac3..96f554b 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -1,27 +1,5 @@ #!/bin/sh -# -# Start seatd -# -[ -f seatd.sock ] && sudo rm seatd.sock -sudo SEATD_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/seatd & - -# seatd is started in the background, so wait for it to come alive -cnt=0 -while ! [ -e ./seatd.sock ] && [ "$cnt" -lt 10 ] -do - sleep 0.1 - cnt=$((cnt+1)) -done - -if ! [ -e ./seatd.sock ] -then - echo "seatd socket not found" - exit 1 -fi - -sudo chmod 777 ./seatd.sock - # Devices that exist on sr.ht if [ -e "/dev/input/event0" ] then @@ -34,6 +12,8 @@ else exit 1 fi +export SEATD_LOGLEVEL=debug +export PATH=$(pwd)/build:$PATH # # Run simpletest a few times # @@ -41,18 +21,12 @@ cnt=0 while [ "$cnt" -lt 2 ] do echo "Simpletest run $((cnt+1))" - if ! SEATD_SOCK=./seatd.sock ./build/simpletest $file + if ! sudo -E seatd-launch ./build/simpletest $file then echo "Simpletest failed" - sudo killall seatd exit 1 fi cnt=$((cnt+1)) done -# -# Wait for it to shut down -# -sudo killall seatd 2>/dev/null - echo "smoketest-seatd completed" From 7d06b34ee248563a6c13d3ccfaa5370c0aa15d2d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 01:14:44 +0200 Subject: [PATCH 119/211] ci: Fix meson flags --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 22dd536..adea8ed 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -10,7 +10,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled -Dexamples=enabled build seatd + meson -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dlibseat-logind=disabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 27391f0..3e1574b 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,7 +9,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Db_sanitize=address -Dlogind=auto -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd + meson -Db_sanitize=address -Dlibseat-logind=auto -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index b9a9eaa..1b4ceba 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -5,14 +5,14 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd + 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 -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled -Dlogind=disabled build seatd + 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 - smoketest-builtin: | From f2a614dcd3b3e473df29a91ca9a7de77ef9b2609 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Aug 2021 08:23:01 +0000 Subject: [PATCH 120/211] seatd-launch: propagate child exit status When the child process exits with a non-zero code or is killed, return with a non-zero code as well. --- seatd-launch/seatd-launch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index ffa6cc6..1b53699 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -101,8 +101,9 @@ int main(int argc, char *argv[]) { goto error_seatd; } + int status = 0; while (true) { - pid_t p = waitpid(child, NULL, 0); + pid_t p = waitpid(child, &status, 0); if (p == child) { break; } else if (p == -1 && errno != EINTR) { @@ -113,7 +114,12 @@ int main(int argc, char *argv[]) { unlink(sockbuf); kill(seatd_child, SIGTERM); - return 0; + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } else { + return 1; + } error_seatd: unlink(sockbuf); From 3a843745c2dee17ec99d3c6b233251a5dc6ff5ad Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Aug 2021 08:23:02 +0000 Subject: [PATCH 121/211] seatd-launch: don't use gotos in child processes While forked (child pid is zero), don't use gotos. These will execute atexit functions and potentially mess up the stdlib. Instead, use _exit. --- seatd-launch/seatd-launch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 1b53699..cf9f93d 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { // TODO: Make seatd accept the numeric UID execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); perror("Could not start seatd"); - goto error; + _exit(1); } close(fds[1]); @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) { setenv("SEATD_SOCK", sockbuf, 1); execv(argv[1], &argv[1]); perror("Could not start target"); - goto error_seatd; + _exit(1); } int status = 0; From 369af8f9e4797be55c4b95facd50dd7cc20565d1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Aug 2021 08:23:03 +0000 Subject: [PATCH 122/211] seatd-launch: check for getpwuid errors --- seatd-launch/seatd-launch.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index cf9f93d..acec145 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -33,7 +33,12 @@ int main(int argc, char *argv[]) { char pipebuf[8]; sprintf(pipebuf, "%d", fds[1]); + struct passwd *user = getpwuid(getuid()); + if (!user) { + perror("getpwuid failed"); + _exit(1); + } // TODO: Make seatd accept the numeric UID execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); From 48727a0b6bc2f7127f2115470be27aa09be7a4a7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 23:00:05 +0200 Subject: [PATCH 123/211] seatd-launch: Command line argument support --- seatd-launch/seatd-launch.c | 46 +++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index acec145..9fd3f23 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -13,10 +13,42 @@ int main(int argc, char *argv[]) { (void)argc; - char sockbuf[256]; - sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); - unlink(sockbuf); + const char *usage = "Usage: seatd-launch [options] [--] command\n" + "\n" + " -h Show this help message\n" + " -s Where to create the seatd socket\n" + " -v Show the version number\n" + "\n"; + + int c; + char *sockpath = NULL; + while ((c = getopt(argc, argv, "vhs:")) != -1) { + switch (c) { + case 's': + sockpath = optarg; + break; + case 'v': + printf("seatd-launch version %s\n", SEATD_VERSION); + return 0; + case 'h': + printf("%s", usage); + return 0; + case '?': + fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); + return 1; + default: + abort(); + } + } + + char sockbuf[256]; + if (sockpath == NULL) { + sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); + sockpath = sockbuf; + } + + unlink(sockpath); int fds[2]; if (pipe(fds) == -1) { @@ -41,7 +73,7 @@ int main(int argc, char *argv[]) { } // TODO: Make seatd accept the numeric UID - execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); + execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockpath, NULL); perror("Could not start seatd"); _exit(1); } @@ -100,7 +132,7 @@ int main(int argc, char *argv[]) { perror("Could not fork target process"); goto error_seatd; } else if (child == 0) { - setenv("SEATD_SOCK", sockbuf, 1); + setenv("SEATD_SOCK", sockpath, 1); execv(argv[1], &argv[1]); perror("Could not start target"); _exit(1); @@ -117,7 +149,7 @@ int main(int argc, char *argv[]) { } } - unlink(sockbuf); + unlink(sockpath); kill(seatd_child, SIGTERM); if (WIFEXITED(status)) { @@ -127,7 +159,7 @@ int main(int argc, char *argv[]) { } error_seatd: - unlink(sockbuf); + unlink(sockpath); kill(seatd_child, SIGTERM); error: return 1; From 2cfc56d5ed87440c58ed7fa538c3a3dbf73fbfc2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 8 Aug 2021 18:16:58 +0200 Subject: [PATCH 124/211] seatd: Improve socket permission error handling chmod/chown errors were logged, but did not result in failure opening the seatd socket. This meant that errors would not get caught by CI. --- seatd/seatd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 826b994..4587e50 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -33,23 +33,27 @@ static int open_socket(const char *path, int uid, int gid) { socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (bind(fd, &addr.generic, size) == -1) { log_errorf("Could not bind socket: %s", strerror(errno)); - close(fd); - return -1; + goto error; } if (listen(fd, LISTEN_BACKLOG) == -1) { log_errorf("Could not listen on socket: %s", strerror(errno)); - close(fd); - return -1; + goto error; } if (uid != -1 || gid != -1) { if (fchown(fd, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); - } else if (fchmod(fd, 0770) == -1) { + goto error; + } + if (fchmod(fd, 0770) == -1) { log_errorf("Could not chmod socket: %s", strerror(errno)); + goto error; } } return fd; +error: + close(fd); + return -1; } int main(int argc, char *argv[]) { From 309650aa4d4be1310b20e7293a3bc0c47aeecf0e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 8 Aug 2021 18:22:17 +0200 Subject: [PATCH 125/211] seatd: Use path in chmod/chown operations c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 snuck in a change which converts chown/chmod to fchown/fchmod using the socket fd. This appears to succeed under Linux, but fails with EINVAL on FreeBSD. As the error handling in this area was flawed, CI failed to catch the regression. Partially revert c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 to fix the regression on FreeBSD. --- seatd/seatd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 4587e50..053d44b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -40,12 +40,12 @@ static int open_socket(const char *path, int uid, int gid) { goto error; } if (uid != -1 || gid != -1) { - if (fchown(fd, uid, gid) == -1) { + 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 (fchmod(fd, 0770) == -1) { + if (chmod(path, 0770) == -1) { log_errorf("Could not chmod socket: %s", strerror(errno)); goto error; } @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { - log_errorf("Could not create server socket: %s", strerror(errno)); + log_error("Could not create server socket"); server_finish(&server); return 1; } From 166feaea3394e00af14418e074ae090e31922f33 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 14 Aug 2021 09:03:23 +0000 Subject: [PATCH 126/211] Make libseat_seat_listener const libseat will never write to that struct. Let's allow callers to make it read-only. --- include/backend.h | 2 +- include/libseat.h | 2 +- libseat/backend/logind.c | 4 ++-- libseat/backend/noop.c | 4 ++-- libseat/backend/seatd.c | 6 +++--- libseat/libseat.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/backend.h b/include/backend.h index 075f48c..8f6ff39 100644 --- a/include/backend.h +++ b/include/backend.h @@ -16,7 +16,7 @@ struct named_backend { }; struct seat_impl { - struct libseat *(*open_seat)(struct libseat_seat_listener *listener, void *data); + struct libseat *(*open_seat)(const struct libseat_seat_listener *listener, void *data); int (*disable_seat)(struct libseat *seat); int (*close_seat)(struct libseat *seat); const char *(*seat_name)(struct libseat *seat); diff --git a/include/libseat.h b/include/libseat.h index 82098ea..2647fb9 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -55,7 +55,7 @@ struct libseat_seat_listener { * Returns a pointer to an opaque libseat struct on success. Returns NULL and * sets errno on error. */ -struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void *userdata); +struct libseat *libseat_open_seat(const struct libseat_seat_listener *listener, void *userdata); /* * Disables a seat, used in response to a disable_seat event. After disabling diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index aa659a6..d62b976 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -30,7 +30,7 @@ struct backend_logind { struct libseat base; - struct libseat_seat_listener *seat_listener; + const struct libseat_seat_listener *seat_listener; void *seat_listener_data; sd_bus *bus; @@ -621,7 +621,7 @@ static int set_type(struct backend_logind *backend, const char *type) { return ret; } -static struct libseat *logind_open_seat(struct libseat_seat_listener *listener, void *data) { +static struct libseat *logind_open_seat(const struct libseat_seat_listener *listener, void *data) { struct backend_logind *backend = calloc(1, sizeof(struct backend_logind)); if (backend == NULL) { return NULL; diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 71d0224..7436c48 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -13,7 +13,7 @@ struct backend_noop { struct libseat base; - struct libseat_seat_listener *seat_listener; + const struct libseat_seat_listener *seat_listener; void *seat_listener_data; bool initial_setup; @@ -103,7 +103,7 @@ static int dispatch_background(struct libseat *base, int timeout) { return 0; } -static struct libseat *noop_open_seat(struct libseat_seat_listener *listener, void *data) { +static struct libseat *noop_open_seat(const struct libseat_seat_listener *listener, void *data) { struct backend_noop *backend = calloc(1, sizeof(struct backend_noop)); if (backend == NULL) { return NULL; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 97971aa..25d8e95 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -33,7 +33,7 @@ struct pending_event { struct backend_seatd { struct libseat base; struct connection connection; - struct libseat_seat_listener *seat_listener; + const struct libseat_seat_listener *seat_listener; void *seat_listener_data; struct linked_list pending_events; bool error; @@ -363,7 +363,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { return predispatch + postdispatch; } -static struct libseat *_open_seat(struct libseat_seat_listener *listener, void *data, int fd) { +static struct libseat *_open_seat(const struct libseat_seat_listener *listener, void *data, int fd) { assert(listener != NULL); assert(listener->enable_seat != NULL && listener->disable_seat != NULL); struct backend_seatd *backend = calloc(1, sizeof(struct backend_seatd)); @@ -411,7 +411,7 @@ alloc_error: return NULL; } -static struct libseat *open_seat(struct libseat_seat_listener *listener, void *data) { +static struct libseat *open_seat(const struct libseat_seat_listener *listener, void *data) { int fd = seatd_connect(); if (fd == -1) { return NULL; diff --git a/libseat/libseat.c b/libseat/libseat.c index 42449a8..8cc9ab2 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -34,7 +34,7 @@ static const struct named_backend impls[] = { #error At least one backend must be enabled #endif -struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void *data) { +struct libseat *libseat_open_seat(const struct libseat_seat_listener *listener, void *data) { if (listener == NULL || listener->enable_seat == NULL || listener->disable_seat == NULL) { errno = EINVAL; return NULL; From 6e7a1db32d1a10593fd3adb95f8243ec322f472d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 15 Aug 2021 13:34:26 +0200 Subject: [PATCH 127/211] logind: Remove redundant null check --- libseat/backend/logind.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index d62b976..cb809e7 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -245,10 +245,6 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { static const char *seat_name(struct libseat *base) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); - - if (backend->seat == NULL) { - return NULL; - } return backend->seat; } From d9ae4c3010abfa1a72f1030afd282b5490747775 Mon Sep 17 00:00:00 2001 From: Greg Depoire--Ferrer Date: Wed, 4 Aug 2021 07:55:28 +0200 Subject: [PATCH 128/211] Revert "libseat: Check euid before using builtin" This reverts commit 1ae6c3b3ddf0ce2a2e1817eb9c74e0c03153df58. A user might want to run the builtin server as non root, if they have permission to use the devices. The check was originally copied from wlroots's direct backend. It was reverted in fa05d3cde68d with a detailed explanation of why root priviledges are not always necessary to use the DRM device. --- libseat/backend/seatd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 25d8e95..3ff54d6 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -606,11 +606,6 @@ static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, return NULL; } - if (geteuid() != 0) { - log_error("Built-in seatd instance requires root privileges"); - return NULL; - } - pid_t pid = fork(); if (pid == -1) { log_errorf("Could not fork: %s", strerror(errno)); From d78859bc9a7ed3c8e62c95087c4a9e56be2e95ce Mon Sep 17 00:00:00 2001 From: Greg Depoire--Ferrer Date: Wed, 4 Aug 2021 10:54:09 +0200 Subject: [PATCH 129/211] libseat: Update builtin backend root requirement documentation The builtin backend no longer requires root, setuid or CAP_SYS_ADMIN. This commit updates the documentation accordingly. --- include/libseat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/libseat.h b/include/libseat.h index 2647fb9..385acd9 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -47,8 +47,10 @@ struct libseat_seat_listener { * The available backends, if enabled at compile-time, are: seatd, logind and * builtin. * - * To use builtin, the process must have CAP_SYS_ADMIN or be root at the time - * of the call. These privileges can be dropped at any point after the call. + * To use builtin, the process must have permission to open and use the seat's + * devices at the time of the call. In the case of DRM devices, this includes + * permission for drmSetMaster(3). These privileges can be dropped at any + * point after the call. * * The returned pointer must be destroyed with libseat_close_seat. * From 038c30f9b1f93fb7fc9514366db3f3aa61a3ca49 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 15 Aug 2021 14:31:50 +0200 Subject: [PATCH 130/211] libseat: Fix build of builtin backend This was regressed by 166feaea3394e00af14418e074ae090e31922f33 which missed the builtin backend when changing struct libseat_seat_listener to being passed around as const. --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 3ff54d6..85df9f5 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -599,7 +599,7 @@ static int set_deathsig(int signal) { #error Unsupported platform #endif -static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, void *data) { +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) { log_errorf("Could not create socket pair: %s", strerror(errno)); From 15b0972bd3b8dbd1dae16ab3eb31a1026a63d17e Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Sun, 8 Aug 2021 19:00:35 +0200 Subject: [PATCH 131/211] meson.build: fix build with gcc < 7 Test if arguments (e.g. -Wimplicit-fallthrough) is available before using it as -Wimplicit-fallthrough has been added only since gcc 7.1 and https://github.com/gcc-mirror/gcc/commit/81fea426da8c4687bb32e6894dc26f00ae211822 and so it will raise the following build failure with gcc < 7: arm-none-linux-gnueabi-gcc: error: unrecognized command line option '-Wimplicit-fallthrough' Fixes: - http://autobuild.buildroot.org/results/0ee6816a7cceebdafd07612677a594bdf68e0790 Signed-off-by: Fabrice Fontaine --- meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 1131b4b..17324ec 100644 --- a/meson.build +++ b/meson.build @@ -22,7 +22,8 @@ if defaultpath == '' endif endif -add_project_arguments( +cc = meson.get_compiler('c') +add_project_arguments(cc.get_supported_arguments( [ '-Wundef', '-Wunused', @@ -41,7 +42,7 @@ add_project_arguments( '-D__BSD_VISIBLE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath) - ], + ]), language: 'c', ) From df3f307b8e013814384723371dbfc549542a3a8f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 23 Apr 2021 00:17:19 +0200 Subject: [PATCH 132/211] seat: Avoid holding a tty fd The kernel Secure Attention Key killer, triggered by SysRq+k, kills all processes that hold an fd referencing the tty. To avoid its attention, we stop storing the fd for the currently active VT in seat state. This has the added benefit of simplifying state a bit. --- include/seat.h | 1 - seatd/seat.c | 51 ++++++++++++++++---------------------------------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/include/seat.h b/include/seat.h index fa5873c..cc243b6 100644 --- a/include/seat.h +++ b/include/seat.h @@ -33,7 +33,6 @@ struct seat { struct client *next_client; bool vt_bound; - int cur_ttyfd; int cur_vt; int session_cnt; }; diff --git a/seatd/seat.c b/seatd/seat.c index 9ad4af2..842928e 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -19,7 +19,7 @@ #include "terminal.h" static int seat_close_client(struct client *client); -static void vt_close(struct seat *seat); +static int vt_close(int vt); struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); @@ -30,7 +30,6 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { seat->vt_bound = vt_bound; seat->seat_name = strdup(seat_name); seat->cur_vt = 0; - seat->cur_ttyfd = -1; if (seat->seat_name == NULL) { free(seat); return NULL; @@ -50,7 +49,6 @@ void seat_destroy(struct seat *seat) { assert(client->seat == seat); client_destroy(client); } - vt_close(seat); linked_list_remove(&seat->link); free(seat->seat_name); free(seat); @@ -66,47 +64,30 @@ static void seat_update_vt(struct seat *seat) { close(tty0fd); } -static int vt_open(struct seat *seat, int vt) { +static int vt_open(int vt) { assert(vt != -1); - if (seat->cur_ttyfd != -1) { - terminal_set_process_switching(seat->cur_ttyfd, true); - close(seat->cur_ttyfd); - } - seat->cur_ttyfd = terminal_open(vt); - if (seat->cur_ttyfd == -1) { + int ttyfd = terminal_open(vt); + if (ttyfd == -1) { log_errorf("Could not open terminal for VT %d: %s", vt, strerror(errno)); return -1; } - terminal_set_process_switching(seat->cur_ttyfd, true); - terminal_set_keyboard(seat->cur_ttyfd, false); - terminal_set_graphics(seat->cur_ttyfd, true); + terminal_set_process_switching(ttyfd, true); + terminal_set_keyboard(ttyfd, false); + terminal_set_graphics(ttyfd, true); + close(ttyfd); return 0; } -static void vt_close_fd(int fd) { - terminal_set_process_switching(fd, true); - terminal_set_keyboard(fd, true); - terminal_set_graphics(fd, false); -} - -static void vt_close(struct seat *seat) { - if (seat->cur_ttyfd == -1) { - return; - } - - vt_close_fd(seat->cur_ttyfd); - close(seat->cur_ttyfd); - seat->cur_ttyfd = -1; -} - -static int vt_close_num(int vt) { +static int vt_close(int vt) { int ttyfd = terminal_open(vt); if (ttyfd == -1) { log_errorf("Could not open terminal to clean up VT %d: %s", vt, strerror(errno)); return -1; } - vt_close_fd(ttyfd); + terminal_set_process_switching(ttyfd, true); + terminal_set_keyboard(ttyfd, true); + terminal_set_graphics(ttyfd, false); close(ttyfd); return 0; } @@ -452,7 +433,7 @@ int seat_open_client(struct seat *seat, struct client *client) { return -1; } - if (seat->vt_bound && vt_open(seat, client->session) == -1) { + if (seat->vt_bound && vt_open(client->session) == -1) { log_error("Could not open VT for client"); goto error; } @@ -477,7 +458,7 @@ int seat_open_client(struct seat *seat, struct client *client) { error: if (seat->vt_bound) { - vt_close(seat); + vt_close(seat->cur_vt); } return -1; } @@ -506,12 +487,12 @@ static int seat_close_client(struct client *client) { // This client was current, but there were no clients // waiting to take this VT, so clean it up. log_debug("Closing active VT"); - vt_close(seat); + vt_close(seat->cur_vt); } else if (!was_current && client->state != CLIENT_CLOSED) { // This client was not current, but as the client was // running, we need to clean up the VT. log_debug("Closing inactive VT"); - vt_close_num(client->session); + vt_close(client->session); } } From 29a6832ca0354f9bdc868533f9399dc3a0fb20e3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Sep 2021 09:14:10 +0000 Subject: [PATCH 133/211] Add .editorconfig Allows text editor auto-configuration. --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..51a7d86 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = 8 From 60c370d4ecdd0645738a6532bed1c9647e2224cb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 2 Sep 2021 23:03:20 +0200 Subject: [PATCH 134/211] seat: Allow new clients when active is pending ack New clients could only be added to a VT bound seat if there were no "active" client, regardless of its actual state. This meant that if one switched from an "active" VT to an "inactive" VT, the seat would be blocked while the "active" client was in CLIENT_PENDING_DISABLE, causing new clients to possibly fail should the old client take its time with the ack. Instead, allow new clients to also be added if there is an active client whose state is CLIENT_PENDING_DISABLE, and there is no client with the new VT as its session ID. --- seatd/seat.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/seatd/seat.c b/seatd/seat.c index 842928e..354273f 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -129,7 +129,8 @@ int seat_add_client(struct seat *seat, struct client *client) { return -1; } - if (seat->vt_bound && seat->active_client != NULL) { + if (seat->vt_bound && seat->active_client != NULL && + seat->active_client->state != CLIENT_PENDING_DISABLE) { log_error("Could not add client: seat is VT-bound and has an active client"); errno = EBUSY; return -1; @@ -148,6 +149,17 @@ int seat_add_client(struct seat *seat, struct client *client) { errno = EINVAL; return -1; } + if (seat->active_client != NULL) { + for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; + elem = elem->next) { + struct client *client = (struct client *)elem; + if (client->session == seat->cur_vt) { + log_error("Could not add client: seat is VT-bound and already has pending client"); + errno = EBUSY; + return -1; + } + } + } client->session = seat->cur_vt; } else { client->session = seat->session_cnt++; From 17cdbe0ad2d0aa563e269cd23c770c75b312bbcb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 8 Sep 2021 20:40:09 +0200 Subject: [PATCH 135/211] seatd-launch: Set socket permissions directly Instead of relying on seatd's user/group arguments, which require turning our UID back into a username, just chmod/chown the socket ourselves once seatd is ready. We also reduce the permissions to just user access, instead of user and group like seatd specifies. --- seatd-launch/seatd-launch.c | 46 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 9fd3f23..f7ed482 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -1,13 +1,12 @@ #include #include -#include #include #include #include #include #include #include -#include +#include #include #include @@ -66,29 +65,13 @@ int main(int argc, char *argv[]) { char pipebuf[8]; sprintf(pipebuf, "%d", fds[1]); - struct passwd *user = getpwuid(getuid()); - if (!user) { - perror("getpwuid failed"); - _exit(1); - } - - // TODO: Make seatd accept the numeric UID - execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockpath, NULL); + execlp("seatd", "seatd", "-n", pipebuf, "-s", sockpath, NULL); perror("Could not start seatd"); _exit(1); } close(fds[1]); - // Drop privileges - if (setgid(getgid()) == -1) { - perror("Could not set gid to drop privileges"); - goto error_seatd; - } - if (setuid(getuid()) == -1) { - perror("Could not set uid to drop privileges"); - goto error_seatd; - } - + // Wait for seatd to be ready char buf[1] = {0}; while (true) { pid_t p = waitpid(seatd_child, NULL, WNOHANG); @@ -127,6 +110,29 @@ int main(int argc, char *argv[]) { } close(fds[0]); + uid_t uid = getuid(); + gid_t gid = getgid(); + + // Restrict access to the socket to just us + if (chown(sockpath, uid, gid) == -1) { + perror("Could not chown seatd socket"); + goto error_seatd; + } + if (chmod(sockpath, 0700) == -1) { + perror("Could not chmod socket"); + goto error; + } + + // Drop privileges + if (setgid(gid) == -1) { + perror("Could not set gid to drop privileges"); + goto error_seatd; + } + if (setuid(uid) == -1) { + perror("Could not set uid to drop privileges"); + goto error_seatd; + } + pid_t child = fork(); if (child == -1) { perror("Could not fork target process"); From e7343ca96f3a59a4e5c846000d37b72f440afd44 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 8 Sep 2021 20:41:48 +0200 Subject: [PATCH 136/211] man: Add simple seatd-launch(1) page --- man/seatd-launch.1.scd | 49 ++++++++++++++++++++++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 man/seatd-launch.1.scd diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd new file mode 100644 index 0000000..7994692 --- /dev/null +++ b/man/seatd-launch.1.scd @@ -0,0 +1,49 @@ +seatd-launch(1) + +# NAME + +seatd-launch - Start a process with its own seatd instance + +# SYNOPSIS + +*seatd-launch* [options] [--] command + +# OPTIONS + +*-h* + Show help message and quit. + +*-s * + Where to create the seatd socket. Defaults to a unique file path. + +*-v* + Show the version number and quit. + +# DESCRIPTION + +seatd-launch starts a seatd instance with a dedicated socket path, waits for it +to be ready, and starts the specified command with SEATD_SOCK set +appropriately. Once the specified command terminates, the seatd instance is +also terminated. + +seatd requires root privileges to perform its tasks. This can be achieved +through SUID of seatd-launch, *sudo(8)*/*doas(1)*, or by running seatd-launch +as root. seatd-launch will drop privileges from the effective user to the real +user before running the specified command. If the real user is root, this is +simply a noop - only run directly as root if you intend for the specified +command to run as root as well. + +seatd-launch serves a similar purpose to the libseat "builtin" backend, but is +superior to it for two reasons: +. The specified command never runs as root +. The standard seatd executable and libseat backend is used + +# SEE ALSO + +The libseat library, **, *seatd(1)* + +# AUTHORS + +Maintained by Kenny Levinsen , who is assisted by other +open-source contributors. For more information about seatd development, see +https://sr.ht/~kennylevinsen/seatd. diff --git a/meson.build b/meson.build index 17324ec..6b2ca2f 100644 --- a/meson.build +++ b/meson.build @@ -247,7 +247,7 @@ if scdoc.found() scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) mandir = get_option('mandir') - foreach src : ['seatd.1.scd'] + foreach src : ['seatd.1.scd', 'seatd-launch.1.scd'] topic = src.split('.')[0] section = src.split('.')[1] output = '@0@.@1@'.format(topic, section) From d1c6bb9a15b5123ec39e675d876e321bf2ebaca9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 8 Sep 2021 20:54:18 +0200 Subject: [PATCH 137/211] seatd-launch: Fix chmod error goto --- seatd-launch/seatd-launch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index f7ed482..0903fe1 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -120,7 +120,7 @@ int main(int argc, char *argv[]) { } if (chmod(sockpath, 0700) == -1) { perror("Could not chmod socket"); - goto error; + goto error_seatd; } // Drop privileges From 3ad9164a896eacffd27588f5b1fd6ea3e0bcd92d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 11 Sep 2021 14:02:44 +0200 Subject: [PATCH 138/211] Bump version to 0.6.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6b2ca2f..a9fc773 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.5.0', + version: '0.6.0', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From da59bea7752799803ff59a714627e53a5857b74d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 11 Sep 2021 15:55:26 +0200 Subject: [PATCH 139/211] man: Add seatd-launch(1) to SEE ALSO of seatd(1) --- man/seatd-launch.1.scd | 2 +- man/seatd.1.scd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index 7994692..b1fb685 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -40,7 +40,7 @@ superior to it for two reasons: # SEE ALSO -The libseat library, **, *seatd(1)* +The libseat library, **, *seatd*(1) # AUTHORS diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 5945782..de95843 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -52,7 +52,7 @@ client-side of the protocol. # SEE ALSO -The libseat library, ** +The libseat library, **, *seatd-launch*(1) # AUTHORS From d5c1a7811bf76abf22045f8f2f5c24fc0d1f6747 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 12 Sep 2021 06:12:33 +0200 Subject: [PATCH 140/211] seatd-launch: respect PATH when looking for command $ seatd-launch sway -c /dev/null Could not start target: No such file or directory --- seatd-launch/seatd-launch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 0903fe1..c362a15 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -139,7 +139,7 @@ int main(int argc, char *argv[]) { goto error_seatd; } else if (child == 0) { setenv("SEATD_SOCK", sockpath, 1); - execv(argv[1], &argv[1]); + execvp(argv[1], &argv[1]); perror("Could not start target"); _exit(1); } From 483dbf76faf9f23117454aa8fc6d22abee3edc89 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 12 Sep 2021 11:44:07 +0200 Subject: [PATCH 141/211] seatd-launch: Use optind to find the command The command indexing had not been updated afer the introduction of getopt, so combining a command with flags would fail. Add error handling for if no command was specified while we're at it. --- seatd-launch/seatd-launch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index c362a15..1877c98 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -41,6 +41,12 @@ int main(int argc, char *argv[]) { } } + if (optind >= argc) { + fprintf(stderr, "A command must be specified\n\n%s", usage); + return 1; + } + char **command = &argv[optind]; + char sockbuf[256]; if (sockpath == NULL) { sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); @@ -139,7 +145,7 @@ int main(int argc, char *argv[]) { goto error_seatd; } else if (child == 0) { setenv("SEATD_SOCK", sockpath, 1); - execvp(argv[1], &argv[1]); + execvp(command[0], command); perror("Could not start target"); _exit(1); } From 8c85c46d2db93fcbb7ff1e0bbeaeb3e4dd0e71a1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 12 Sep 2021 12:04:38 +0200 Subject: [PATCH 142/211] man/seatd-launch: Make mssage about root clearer --- man/seatd-launch.1.scd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index b1fb685..d882ba5 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -27,11 +27,11 @@ appropriately. Once the specified command terminates, the seatd instance is also terminated. seatd requires root privileges to perform its tasks. This can be achieved -through SUID of seatd-launch, *sudo(8)*/*doas(1)*, or by running seatd-launch -as root. seatd-launch will drop privileges from the effective user to the real -user before running the specified command. If the real user is root, this is -simply a noop - only run directly as root if you intend for the specified -command to run as root as well. +through SUID of seatd-launch or by running seatd-launch as root. seatd-launch +will drop privileges from the effective user to the real user before running +the specified command. If the real user is root, this is simply a noop. You +should only run seatd-launch as root if you intend for the specified command to +run as root as well. seatd-launch serves a similar purpose to the libseat "builtin" backend, but is superior to it for two reasons: From fe600eac2be9bd09d6c9746cf273a7eaed4e6f7f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Sep 2021 09:54:18 +0000 Subject: [PATCH 143/211] seatd-launch: exit with status >128 if child is signalled Mimick shells and exit with a status >128 if our child has been signalled. Exiting with 128 + signal number is what most shells do (POSIX only requires them to exit with >128). --- man/seatd-launch.1.scd | 8 ++++++++ seatd-launch/seatd-launch.c | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index d882ba5..9234203 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -38,6 +38,14 @@ superior to it for two reasons: . The specified command never runs as root . The standard seatd executable and libseat backend is used +# EXIT STATUS + +seatd-launch exits with the status of its child. When the child terminates on +a signal _N_, seatd-launch exits with the status 128 + _N_. + +If seatd-launch fails because of another error, it exits with a non-zero +status. + # SEE ALSO The libseat library, **, *seatd*(1) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 1877c98..ba61f5d 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -166,8 +166,10 @@ int main(int argc, char *argv[]) { if (WIFEXITED(status)) { return WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + return 128 + WTERMSIG(status); } else { - return 1; + abort(); // unreachable } error_seatd: From 4e3b7b3bb605daf7337db0c922904c251c58289a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Sep 2021 09:59:46 +0000 Subject: [PATCH 144/211] seatd-launch: print unlink/kill errors Makes it easier to find out that something went wrong. --- seatd-launch/seatd-launch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index ba61f5d..b9d33d7 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -161,8 +161,12 @@ int main(int argc, char *argv[]) { } } - unlink(sockpath); - kill(seatd_child, SIGTERM); + if (unlink(sockpath) != 0) { + perror("Could not unlink socket"); + } + if (kill(seatd_child, SIGTERM) != 0) { + perror("Could not kill seatd"); + } if (WIFEXITED(status)) { return WEXITSTATUS(status); From 66becee6dac74384439838c5c40624ae043fb7bf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 14 Sep 2021 11:58:56 +0200 Subject: [PATCH 145/211] Bump version to 0.6.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a9fc773..999380d 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.0', + version: '0.6.1', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From 4091ba2c07efde82a109fa8a07db77c814e90e5c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 15 Sep 2021 23:30:53 +0200 Subject: [PATCH 146/211] ci: Install seatd instead of manipulating PATH --- .builds/alpine.yml | 1 + .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + .builds/smoketest-seatd.sh | 3 +-- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index adea8ed..20f5fef 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -13,6 +13,7 @@ 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: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 3e1574b..3f7463c 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -12,6 +12,7 @@ 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: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 1b4ceba..79bee15 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -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 + sudo ninja -C build install timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index 96f554b..f471928 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -13,7 +13,6 @@ else fi export SEATD_LOGLEVEL=debug -export PATH=$(pwd)/build:$PATH # # Run simpletest a few times # @@ -21,7 +20,7 @@ cnt=0 while [ "$cnt" -lt 2 ] do echo "Simpletest run $((cnt+1))" - if ! sudo -E seatd-launch ./build/simpletest $file + if ! sudo -E ./build/seatd-launch ./build/simpletest $file then echo "Simpletest failed" exit 1 From 907b75de1ae5ec415a99889faecaf05b36bea31e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 15 Sep 2021 23:34:02 +0200 Subject: [PATCH 147/211] seatd-launch: Use absolute path for seatd We previously used execlp to execute seatd, which had the effect of searching PATH for the executable. This allowed the caller to control what executable was run, which is bad if SUID has been set. Instead, expose the absolute install path for seatd from meason as a define, and use that in a call to execv. --- meson.build | 5 ++++- seatd-launch/seatd-launch.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 999380d..b6892c7 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,8 @@ if defaultpath == '' endif endif +seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir')) + cc = meson.get_compiler('c') add_project_arguments(cc.get_supported_arguments( [ @@ -41,7 +43,8 @@ add_project_arguments(cc.get_supported_arguments( '-D_XOPEN_SOURCE=700', '-D__BSD_VISIBLE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), - '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath) + '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), + '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), ]), language: 'c', ) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index b9d33d7..7b41bb6 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -68,10 +68,11 @@ int main(int argc, char *argv[]) { } else if (seatd_child == 0) { close(fds[0]); - char pipebuf[8]; - sprintf(pipebuf, "%d", fds[1]); + char pipebuf[16] = {0}; + snprintf(pipebuf, sizeof pipebuf, "%d", fds[1]); - execlp("seatd", "seatd", "-n", pipebuf, "-s", sockpath, NULL); + char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, NULL}; + execv(SEATD_INSTALLPATH, command); perror("Could not start seatd"); _exit(1); } From ebf512c2bf74b1286d2f243c2f78daa64114d81d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 16 Sep 2021 00:10:56 +0200 Subject: [PATCH 148/211] seatd-launch: Specify exact environment to seatd The parent environment might contain nasty things. Create a new environment for the seatd process containing only the environment variables we care about. For now, that's only SEATD_LOGLEVEL. --- seatd-launch/seatd-launch.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 7b41bb6..69ca86a 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -71,8 +71,16 @@ int main(int argc, char *argv[]) { char pipebuf[16] = {0}; snprintf(pipebuf, sizeof pipebuf, "%d", fds[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}; - execv(SEATD_INSTALLPATH, command); + execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); } From 0f20175752b7b11a5c66070b2dedc4cf8716d107 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 16 Sep 2021 01:07:42 +0200 Subject: [PATCH 149/211] Bump version to 0.6.2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b6892c7..e6c80a4 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.1', + version: '0.6.2', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From 2eee9aa445e3f9dc6a7ca115489f87b10f60b9ba Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 20 Sep 2021 23:43:10 +0200 Subject: [PATCH 150/211] seatd: Implement ping request to wake up later When device open or close messages are sent to seatd, libseat must read messages from the socket until it sees the associated response message. This means that it may drain enable/disable seat events from the socket, queueing them internally for deferred processing. As the socket is drained, the caller will not wake from a poll and have no reason to dispatch libseat. To ensure that these messages would not be left in the queue, 6fa82930d0c5660eea3102989c765dc864514e36 made it so that open/close calls would execute all queued events just before returning. Unfortunately, this had the side-effect of having events fire from the stack of libseat_open_device or libseat_close_device, which we now see cause problems in compositors. Specifically, an issue has been observed where libinput end up calling libseat_close_device, which in turn dispatch a disable seat event that calls libinput_suspend. libinput does not like this. Instead, remove the execution from libseat_open_device and libseat_close_device, and instead make a "ping" request to seatd if events have been queued. The response to this will wake us up and ensure that dispatch is called. --- include/protocol.h | 2 ++ libseat/backend/seatd.c | 45 +++++++++++++++++++++++++++++++++++++---- seatd/client.c | 22 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/include/protocol.h b/include/protocol.h index b3361ba..cb994fc 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -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,6 +23,7 @@ #define SERVER_DEVICE_CLOSED SERVER_EVENT(4) #define SERVER_DISABLE_SEAT SERVER_EVENT(5) #define SERVER_ENABLE_SEAT SERVER_EVENT(6) +#define SERVER_PONG SERVER_EVENT(7) #define SERVER_ERROR SERVER_EVENT(0x7FFF) #include diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 85df9f5..26308d1 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -36,6 +36,7 @@ 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]; @@ -243,6 +244,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 +457,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 +518,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 +553,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; } diff --git a/seatd/client.c b/seatd/client.c index 1bfe94a..220c5d3 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -309,6 +309,20 @@ 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; switch (opcode) { @@ -372,6 +386,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; From db08fb921f8ea13202a487dcea2fdd3914b87dfd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 20 Sep 2021 23:43:11 +0200 Subject: [PATCH 151/211] logind: Send ping to wake us up later sd_bus_call drains received messages into the receive queue, and peeks for its own return value. It does not dispatch the receive queue. As the socket is drained, the caller will not wake from a poll and have no reason to dispatch libseat. This has gone unnoticed largely due to logind sending an event for every device, making it unlikely that no unread message will be left on the socket. Like we have done for seatd, we fix this by sending a "ping" request to logind if anything is left in our receive queue as reported by sd_bus_get_events. The response to this will wake us up and ensure that dispatch is called. --- libseat/backend/logind.c | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index cb809e7..dd050ce 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -41,6 +41,7 @@ struct backend_logind { bool active; bool initial_setup; + bool awaiting_pong; int has_drm; }; @@ -67,6 +68,48 @@ 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; + struct backend_logind *session = userdata; + if (sd_bus_message_is_method_error(m, NULL)) { + const sd_bus_error *error = sd_bus_message_get_error(m); + log_errorf("Ping failed: %s: %s", error->name, error->message); + return -1; + } + session->awaiting_pong = false; + return 0; +} + +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, NULL, ""); + if (ret < 0) { + return ret; + } + return 0; +} + +static void check_pending_events(struct backend_logind *backend) { + if (sd_bus_get_events(backend->bus) <= 0) { + 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 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; + } + backend->awaiting_pong = true; +} + static int open_device(struct libseat *base, const char *path, int *fd) { struct backend_logind *session = backend_logind_from_libseat_backend(base); @@ -113,9 +156,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 +195,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 +218,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; } From e2baadc23047edaccc4a7d3d95e6ba8c30f75851 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 21 Sep 2021 12:46:52 +0200 Subject: [PATCH 152/211] clang-format: Fix alignment --- .clang-format | 2 +- common/drm.c | 4 ++-- common/terminal.c | 4 ++-- include/protocol.h | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.clang-format b/.clang-format index c182735..28723ad 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ IndentWidth: 8 TabWidth: 8 ContinuationIndentWidth: 8 -UseTab: Always +UseTab: ForContinuationAndIndentation ColumnLimit: 100 AlignConsecutiveMacros: true diff --git a/common/drm.c b/common/drm.c index 897028c..9591dc0 100644 --- a/common/drm.c +++ b/common/drm.c @@ -9,8 +9,8 @@ #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) diff --git a/common/terminal.c b/common/terminal.c index 6274957..0c3466f 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -13,14 +13,14 @@ #include #define K_ENABLE K_UNICODE #define K_DISABLE K_OFF -#define FRSIG 0 +#define FRSIG 0 #elif defined(__FreeBSD__) #include #include #include #define K_ENABLE K_XLATE #define K_DISABLE K_RAW -#define FRSIG SIGIO +#define FRSIG SIGIO #else #error Unsupported platform #endif diff --git a/include/protocol.h b/include/protocol.h index cb994fc..25133e5 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -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,7 +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 CLIENT_PING CLIENT_EVENT(7) #define SERVER_SEAT_OPENED SERVER_EVENT(1) #define SERVER_SEAT_CLOSED SERVER_EVENT(2) @@ -23,8 +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_PONG SERVER_EVENT(7) -#define SERVER_ERROR SERVER_EVENT(0x7FFF) +#define SERVER_PONG SERVER_EVENT(7) +#define SERVER_ERROR SERVER_EVENT(0x7FFF) #include From 1c376ca9b13458b1e4ad0da20c8d35729fa09d4b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 21 Sep 2021 13:11:55 +0200 Subject: [PATCH 153/211] ci: Inline smoketest into build scripts The smoketest script has gotten significantly simpler, and can simply be inlined into the build scripts if we don't care about running the tests twice. This should fix CI for mailing list patches. --- .builds/alpine.yml | 4 ++-- .builds/archlinux.yml | 4 ++-- .builds/freebsd.yml | 4 ++-- .builds/smoketest-builtin.sh | 30 ------------------------------ .builds/smoketest-seatd.sh | 31 ------------------------------- 5 files changed, 6 insertions(+), 67 deletions(-) delete mode 100755 .builds/smoketest-builtin.sh delete mode 100755 .builds/smoketest-seatd.sh diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 20f5fef..bb8904a 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -20,9 +20,9 @@ tasks: 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 SEATD_LOGLEVEL=debug ./build/seatd-launch ./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 diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 3f7463c..bc3229a 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -19,6 +19,6 @@ tasks: 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 SEATD_LOGLEVEL=debug ./build/seatd-launch ./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 diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 79bee15..b4bc7da 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -15,6 +15,6 @@ tasks: meson -Db_lundef=false -Db_sanitize=address -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled -Dlibseat-logind=disabled build seatd ninja -C build sudo ninja -C build install - timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./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 diff --git a/.builds/smoketest-builtin.sh b/.builds/smoketest-builtin.sh deleted file mode 100755 index 332c3f9..0000000 --- a/.builds/smoketest-builtin.sh +++ /dev/null @@ -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" diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh deleted file mode 100755 index f471928..0000000 --- a/.builds/smoketest-seatd.sh +++ /dev/null @@ -1,31 +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 -# -# Run simpletest a few times -# -cnt=0 -while [ "$cnt" -lt 2 ] -do - echo "Simpletest run $((cnt+1))" - if ! sudo -E ./build/seatd-launch ./build/simpletest $file - then - echo "Simpletest failed" - exit 1 - fi - cnt=$((cnt+1)) -done - -echo "smoketest-seatd completed" From 262ccef84eddf3714183b80729a157504615468e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Sep 2021 09:40:02 +0000 Subject: [PATCH 154/211] logind: check if session is active on startup Up until now we assumed the session was always active on startup. This might not be the case. Instead, read the current value of the Active property. --- libseat/backend/logind.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index dd050ce..ceafc6c 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -303,6 +303,7 @@ static bool 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) { @@ -314,6 +315,22 @@ static bool session_activate(struct backend_logind *session) { return ret >= 0; } +static bool 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 >= 0; +} + static bool take_control(struct backend_logind *session) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -699,6 +716,10 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list goto error; } + if (!session_check_active(backend)) { + goto error; + } + if (!take_control(backend)) { goto error; } @@ -709,7 +730,6 @@ 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; From d2193b45ff3098515115b317878814dc32098294 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Sep 2021 09:44:44 +0000 Subject: [PATCH 155/211] examples/simpletest: check for libseat_dispatch failures --- examples/simpletest/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/simpletest/main.c b/examples/simpletest/main.c index aeeace2..6f94cf5 100644 --- a/examples/simpletest/main.c +++ b/examples/simpletest/main.c @@ -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"); From 8e5c00e7c8d9113b69a880dc6d7feecb0b3eed41 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Sep 2021 23:04:40 +0200 Subject: [PATCH 156/211] logind: Improve error handling in open_seat errno was not being set by open_seat in most cases, leading to simpletest possibly failing with "libseat_open_seat() failed: Success". --- libseat/backend/logind.c | 63 +++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index ceafc6c..e96af6a 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -299,7 +299,7 @@ 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; @@ -312,10 +312,10 @@ 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 session_check_active(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, @@ -328,10 +328,10 @@ static bool session_check_active(struct backend_logind *session) { } sd_bus_error_free(&error); - return ret >= 0; + return ret; } -static bool take_control(struct backend_logind *session) { +static int take_control(struct backend_logind *session) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -344,7 +344,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) { @@ -530,7 +530,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"; @@ -540,34 +540,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; @@ -592,10 +592,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; @@ -620,10 +620,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; @@ -656,12 +656,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) { @@ -686,11 +686,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; } @@ -700,27 +702,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 (!session_check_active(backend)) { + ret = session_check_active(backend); + if (ret < 0) { goto error; } - if (!take_control(backend)) { + ret = take_control(backend); + if (ret < 0) { goto error; } @@ -738,6 +746,7 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list error: destroy(backend); + errno = -ret; return NULL; } From ec0d6565bbe81f1e371da0ddff39ee4c4124ffcf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Sep 2021 23:06:59 +0200 Subject: [PATCH 157/211] ci: Add logind smoketest to arch --- .builds/archlinux.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index bc3229a..da300c8 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -22,3 +22,9 @@ tasks: timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 + - smoketest-logind: | + # 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 From e35c9cd02e95ec8a76bb4bb82f801a795e135bc9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 5 Oct 2021 10:05:25 +0200 Subject: [PATCH 158/211] logind: Set userdata for ping_handler --- libseat/backend/logind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index e96af6a..5a10c75 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -83,7 +83,7 @@ static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_err 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, NULL, ""); + "Ping", ping_handler, backend, ""); if (ret < 0) { return ret; } From 88db55f6068c1c01d85b61aa6adff0a6b2a8dce8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 19 Oct 2021 21:39:17 +0200 Subject: [PATCH 159/211] Bump version to 0.6.3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e6c80a4..d8fd25d 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.2', + version: '0.6.3', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From cb7a94378b96b9c7e0da8ea8e3a2e756b4976d35 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:30:28 +0000 Subject: [PATCH 160/211] 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. --- seatd/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/server.c b/seatd/server.c index 0a08f50..8e59c5d 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -123,8 +123,8 @@ 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; } From 88529f08567fabf28432d17dd94b863ea61d554d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:33:07 +0000 Subject: [PATCH 161/211] seatd: don't log errno on EVENT_ERROR errno won't be set when poll returns EVENT_ERROR. --- seatd/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/server.c b/seatd/server.c index 8e59c5d..8ead54d 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -146,7 +146,7 @@ int server_handle_connection(int fd, uint32_t mask, void *data) { if (mask & (EVENT_ERROR | EVENT_HANGUP)) { shutdown(fd, SHUT_RDWR); server->running = false; - log_errorf("Server socket received an error: %s", strerror(errno)); + log_error("Server socket received an error"); return -1; } From 69cf5c36e05c64597063dd8c4d83d3e036547451 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 26 Oct 2021 12:56:26 +0000 Subject: [PATCH 162/211] 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. --- meson.build | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index d8fd25d..206cde1 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,18 @@ endif seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir')) cc = meson.get_compiler('c') + +add_project_arguments( + [ + '-D_XOPEN_SOURCE=700', + '-D__BSD_VISIBLE', + '-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', @@ -40,11 +52,6 @@ add_project_arguments(cc.get_supported_arguments( '-Wno-unused-command-line-argument', '-Wvla', '-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', ) From d92fa01f884e94262e4c7184be62efaf8a00a634 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 21:17:51 +0000 Subject: [PATCH 163/211] 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. --- libseat/backend/logind.c | 4 ++-- meson.build | 19 ++++++------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 5a10c75..bfb02cf 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -13,10 +13,10 @@ #include #include -#if defined(HAVE_ELOGIND) +#if defined(HAVE_LIBELOGIND) #include #include -#elif defined(HAVE_SYSTEMD) +#elif defined(HAVE_LIBSYSTEMD) #include #include #else diff --git a/meson.build b/meson.build index 206cde1..b5d00c6 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '0.6.3', license: 'MIT', - meson_version: '>=0.56.0', + meson_version: '>=0.60.0', default_options: [ 'c_std=c11', 'warning_level=3', @@ -126,26 +126,19 @@ if with_seatd 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') + add_project_arguments('-DHAVE_@0@=1'.format(logind.name().to_upper()), language: 'c') private_files += [ 'libseat/backend/logind.c', 'common/drm.c', @@ -278,7 +271,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) From f381e22955d9bcffd1c47c70626f22972e5af1db Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 21:20:05 +0000 Subject: [PATCH 164/211] build: don't use sh for scdoc Just use the built-in feed/capture Meson options instead. --- meson.build | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index b5d00c6..c313294 100644 --- a/meson.build +++ b/meson.build @@ -247,7 +247,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 +258,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) ) From 936ff9dbea9148f0b5e4892c392337060bee5860 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 14 Dec 2021 11:14:39 +0000 Subject: [PATCH 165/211] 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']) --- meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meson.build b/meson.build index c313294..960c3b6 100644 --- a/meson.build +++ b/meson.build @@ -200,6 +200,8 @@ libseat = declare_dependency( variables: libseat_vars, ) +meson.override_dependency('libseat', libseat) + if with_server executable( 'seatd', From 96a5de88595cb8ddc41a4beb72d213d1f8bfdc61 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Dec 2021 07:46:48 +0000 Subject: [PATCH 166/211] readme: add irc:// link This allows users to just click the link to join the IRC channel. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aa9e99..2ed6e8b 100644 --- a/README.md +++ b/README.md @@ -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). From b47c79d73123052b20bc853b544c10274ab29fa6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 9 Feb 2022 23:21:18 +0100 Subject: [PATCH 167/211] libseat: Use SOCK_CLOEXEC and SOCK_NONBLOCK This both simplifies our code and fixes an exec fd leak when using builtin or noop backends. --- libseat/backend/noop.c | 2 +- libseat/backend/seatd.c | 20 ++------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 7436c48..f69aac6 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -109,7 +109,7 @@ 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; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 26308d1..6e90713 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -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; @@ -638,7 +622,7 @@ static int set_deathsig(int signal) { 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; } From f128359332ac33d5ef0c2e91830059fb1c1ef923 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 15 Feb 2022 13:24:41 +0100 Subject: [PATCH 168/211] 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. --- libseat/backend/logind.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index bfb02cf..53523c8 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -41,7 +41,6 @@ struct backend_logind { bool active; bool initial_setup; - bool awaiting_pong; int has_drm; }; @@ -70,13 +69,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 +89,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 +106,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 +284,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { total_dispatched += dispatched; } } + check_pending_events(backend); return total_dispatched; } @@ -742,6 +741,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: From 157ce685658c19b51caa091601240940267c0940 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:27:56 +0100 Subject: [PATCH 169/211] seatd: Remove SOCK_PATH and improve cleanup SOCK_PATH is made redundant by the -s command-line argument added in a98e0c4ce90347d37370f2debcbed8ae9678a990. 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. --- seatd/seatd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 053d44b..8480350 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) { int c; int uid = -1, gid = -1; int readiness = -1; - const char *socket_path = getenv("SEATD_SOCK"); + const char *socket_path = SEATD_DEFAULTPATH; while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { switch (c) { case 'n': @@ -131,11 +131,14 @@ 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"); + struct stat st; + if (stat(socket_path, &st) == 0) { + if (!S_ISSOCK(st.st_mode)) { + log_errorf("Non-socket file found at socket path %s, refusing to start", + socket_path); + return 1; + } else { + log_infof("Removing leftover socket at %s", socket_path); unlink(socket_path); } } From 0864f6a3ac8ca8263490269ecc7fdf4c1cd59850 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:37:26 +0100 Subject: [PATCH 170/211] seatd: Ensure socket gets unlinked on error --- seatd/seatd.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 8480350..c2ce411 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -145,22 +145,21 @@ int main(int argc, char *argv[]) { 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 ret = 1; int socket_fd = open_socket(socket_path, 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"); @@ -175,12 +174,16 @@ 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; } } - server_finish(&server); + ret = 0; + +error_socket: unlink(socket_path); +error_server: + server_finish(&server); log_info("seatd stopped"); - return 0; + return ret; } From 32d06482d3aeaac166d76912fcba53fa8dfb2fcf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:44:27 +0100 Subject: [PATCH 171/211] 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. --- seatd-launch/seatd-launch.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 69ca86a..0075efb 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -53,8 +53,6 @@ int main(int argc, char *argv[]) { sockpath = sockbuf; } - unlink(sockpath); - int fds[2]; if (pipe(fds) == -1) { perror("Could not create pipe"); @@ -170,9 +168,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 +181,6 @@ int main(int argc, char *argv[]) { } error_seatd: - unlink(sockpath); kill(seatd_child, SIGTERM); error: return 1; From 10658dc5439db429af0088295a051c53925a4416 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:46:48 +0100 Subject: [PATCH 172/211] 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. --- seatd-launch/seatd-launch.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 0075efb..4f15616 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -15,18 +15,13 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" - " -h Show this help message\n" - " -s Where to create the seatd socket\n" - " -v Show the version number\n" + " -h Show this help message\n" + " -v Show the version number\n" "\n"; int c; - char *sockpath = NULL; - while ((c = getopt(argc, argv, "vhs:")) != -1) { + while ((c = getopt(argc, argv, "vh")) != -1) { switch (c) { - case 's': - sockpath = optarg; - break; case 'v': printf("seatd-launch version %s\n", SEATD_VERSION); return 0; @@ -47,11 +42,8 @@ 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; - } + char sockpath[256]; + sprintf(sockpath, "/tmp/seatd.%d.sock", getpid()); int fds[2]; if (pipe(fds) == -1) { From a44476ce65af5c192860130cb25b0ce17cec2651 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 12:04:09 +0100 Subject: [PATCH 173/211] seatd: Fix usage rendering --- seatd/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index c2ce411..0d9274b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd [options]\n" "\n" " -h Show this help message\n" - " -n FD to notify readiness on\n" + " -n FD to notify readiness on\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" From ed90ed62cdf1c4e7d59e4d279a5bf946b93057dd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 21:27:14 +0100 Subject: [PATCH 174/211] 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. --- seatd-launch/seatd-launch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 4f15616..8057ba7 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -42,8 +42,8 @@ int main(int argc, char *argv[]) { } char **command = &argv[optind]; - char sockpath[256]; - sprintf(sockpath, "/tmp/seatd.%d.sock", getpid()); + char sockpath[32]; + snprintf(sockpath, sizeof sockpath, "/tmp/seatd.%d.sock", getpid()); int fds[2]; if (pipe(fds) == -1) { From 3eb0db57bb1c23b5157279223f248d58d9662aae Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 21:33:06 +0100 Subject: [PATCH 175/211] seatd-launch: Minor readability improvements --- seatd-launch/seatd-launch.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 8057ba7..d03a50f 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -11,8 +11,6 @@ #include int main(int argc, char *argv[]) { - (void)argc; - const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" " -h Show this help message\n" @@ -45,21 +43,22 @@ int main(int argc, char *argv[]) { char sockpath[32]; snprintf(sockpath, sizeof sockpath, "/tmp/seatd.%d.sock", getpid()); - 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}; @@ -74,7 +73,7 @@ int main(int argc, char *argv[]) { perror("Could not start seatd"); _exit(1); } - close(fds[1]); + close(readiness_pipe[1]); // Wait for seatd to be ready char buf[1] = {0}; @@ -89,7 +88,7 @@ int main(int argc, char *argv[]) { } struct pollfd fd = { - .fd = fds[0], + .fd = readiness_pipe[0], .events = POLLIN, }; @@ -104,7 +103,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; @@ -113,7 +112,7 @@ int main(int argc, char *argv[]) { } } } - close(fds[0]); + close(readiness_pipe[0]); uid_t uid = getuid(); gid_t gid = getgid(); From 9bbdf0f0b8d383edd1d621507c04db0a5382a5af Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 19:05:49 +0100 Subject: [PATCH 176/211] 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. --- man/seatd-launch.1.scd | 4 ++++ man/seatd.1.scd | 16 ++++------------ seatd-launch/seatd-launch.c | 23 +++++++++++------------ seatd/seatd.c | 35 ++++++++++++++++++++--------------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index 9234203..d66ad3e 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -10,6 +10,10 @@ seatd-launch - Start a process with its own seatd instance # OPTIONS +*-l * + Log-level to pass to seatd. See *seatd*(1) for information about + available log-levels. + *-h* Show help message and quit. diff --git a/man/seatd.1.scd b/man/seatd.1.scd index de95843..2de4326 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -27,6 +27,10 @@ seatd - A seat management daemon *-s * Where to create the seatd socket. Defaults to `/run/seatd.sock`. +*-l * + Log-level to use. Must be one of debug, info, error or silent. Defaults + to error. + *-v* Show the version number and quit. @@ -38,18 +42,6 @@ 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. -# 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" - # SEE ALSO The libseat library, **, *seatd-launch*(1) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index d03a50f..f8ab8d4 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -13,13 +13,19 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" - " -h Show this help message\n" - " -v Show the version number\n" + " -l Log-level to pass to seatd\n" + " -h Show this help message\n" + " -v Show the version number\n" "\n"; int c; - while ((c = getopt(argc, argv, "vh")) != -1) { + char loglevel[16] = "info"; + while ((c = getopt(argc, argv, "vhl:")) != -1) { switch (c) { + case 'l': + strncpy(loglevel, optarg, sizeof loglevel); + loglevel[sizeof loglevel - 1] = '\0'; + break; case 'v': printf("seatd-launch version %s\n", SEATD_VERSION); return 0; @@ -60,15 +66,8 @@ int main(int argc, char *argv[]) { char pipebuf[16] = {0}; 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, "-s", sockpath, "-l", loglevel, NULL}; execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); diff --git a/seatd/seatd.c b/seatd/seatd.c index 0d9274b..2a41146 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -57,20 +57,6 @@ 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" @@ -78,14 +64,16 @@ int main(int argc, char *argv[]) { " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" + " -l 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; + enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; const char *socket_path = SEATD_DEFAULTPATH; - while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { + while ((c = getopt(argc, argv, "vhn:s:g:u:l:")) != -1) { switch (c) { case 'n': readiness = atoi(optarg); @@ -117,6 +105,20 @@ 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 'v': printf("seatd version %s\n", SEATD_VERSION); return 0; @@ -131,6 +133,9 @@ int main(int argc, char *argv[]) { } } + log_init(); + libseat_set_log_level(level); + struct stat st; if (stat(socket_path, &st) == 0) { if (!S_ISSOCK(st.st_mode)) { From 466efea49bc6ab5672555c31f04b39741c502c70 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 19:37:49 +0100 Subject: [PATCH 177/211] seatd: Handle socket unlink errors This ensures early failure and better error messages. --- seatd/seatd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 2a41146..ef6c781 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -144,7 +144,10 @@ int main(int argc, char *argv[]) { return 1; } else { log_infof("Removing leftover socket at %s", socket_path); - unlink(socket_path); + if (unlink(socket_path) == -1) { + log_errorf("Could not remove leftover socket: %s", strerror(errno)); + return 1; + } } } @@ -186,7 +189,9 @@ int main(int argc, char *argv[]) { ret = 0; error_socket: - unlink(socket_path); + if (unlink(socket_path) == -1) { + log_errorf("Could not remove socket: %s", strerror(errno)); + } error_server: server_finish(&server); log_info("seatd stopped"); From 0d6bdf4f01e5be10c29dd786f2531b96e1d935cd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 20:25:22 +0100 Subject: [PATCH 178/211] 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. --- man/seatd-launch.1.scd | 3 --- man/seatd.1.scd | 5 ++-- seatd-launch/seatd-launch.c | 11 +++----- seatd/seatd.c | 53 ++++++++++++++++++++++++++----------- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index d66ad3e..73d302d 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -17,9 +17,6 @@ seatd-launch - Start a process with its own seatd instance *-h* Show help message and quit. -*-s * - Where to create the seatd socket. Defaults to a unique file path. - *-v* Show the version number and quit. diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 2de4326..f599a23 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -24,9 +24,6 @@ seatd - A seat management daemon *-g * Group to own the seatd socket. -*-s * - Where to create the seatd socket. Defaults to `/run/seatd.sock`. - *-l * Log-level to use. Must be one of debug, info, error or silent. Defaults to error. @@ -42,6 +39,8 @@ 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. + # SEE ALSO The libseat library, **, *seatd-launch*(1) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index f8ab8d4..329ccef 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -46,9 +46,6 @@ int main(int argc, char *argv[]) { } char **command = &argv[optind]; - char sockpath[32]; - snprintf(sockpath, sizeof sockpath, "/tmp/seatd.%d.sock", getpid()); - int readiness_pipe[2]; if (pipe(readiness_pipe) == -1) { perror("Could not create pipe"); @@ -67,7 +64,7 @@ int main(int argc, char *argv[]) { snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]); char *env[1] = {NULL}; - char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, "-l", loglevel, NULL}; + char *command[] = {"seatd", "-n", pipebuf, "-l", loglevel, "-z", NULL}; execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); @@ -117,11 +114,11 @@ int main(int argc, char *argv[]) { 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; } @@ -141,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); diff --git a/seatd/seatd.c b/seatd/seatd.c index ef6c781..f6bad9b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -40,15 +40,15 @@ static int open_socket(const char *path, int uid, int gid) { goto error; } if (uid != -1 || gid != -1) { + if (chmod(path, 0770) == -1) { + log_errorf("Could not chmod socket: %s", strerror(errno)); + goto error; + } if (chown(path, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); goto error; } - if (chmod(path, 0770) == -1) { - log_errorf("Could not chmod socket: %s", strerror(errno)); - goto error; - } } return fd; error: @@ -63,7 +63,6 @@ int main(int argc, char *argv[]) { " -n FD to notify readiness on\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" - " -s Where to create the seatd socket\n" " -l Log-level, one of debug, info, error or silent\n" " -v Show the version number\n" "\n"; @@ -71,9 +70,10 @@ int main(int argc, char *argv[]) { int c; int uid = -1, gid = -1; int readiness = -1; + bool unlink_existing_socket = true; + bool chown_socket = true; enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; - const char *socket_path = SEATD_DEFAULTPATH; - while ((c = getopt(argc, argv, "vhn:s:g:u:l:")) != -1) { + while ((c = getopt(argc, argv, "vhn:g:u:l:z")) != -1) { switch (c) { case 'n': readiness = atoi(optarg); @@ -82,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); @@ -96,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); @@ -119,6 +124,17 @@ int main(int argc, char *argv[]) { 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; @@ -137,14 +153,19 @@ int main(int argc, char *argv[]) { libseat_set_log_level(level); struct stat st; - if (stat(socket_path, &st) == 0) { + 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", - socket_path); + 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 { - log_infof("Removing leftover socket at %s", socket_path); - if (unlink(socket_path) == -1) { + // 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; } @@ -158,7 +179,7 @@ int main(int argc, char *argv[]) { } int ret = 1; - int socket_fd = open_socket(socket_path, uid, gid); + int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid); if (socket_fd == -1) { log_error("Could not create server socket"); goto error_server; @@ -189,7 +210,7 @@ int main(int argc, char *argv[]) { ret = 0; error_socket: - if (unlink(socket_path) == -1) { + if (unlink(SEATD_DEFAULTPATH) == -1) { log_errorf("Could not remove socket: %s", strerror(errno)); } error_server: From ae42d05513189c2215916c5586e9f8fb74c4d5e7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 22:56:42 +0100 Subject: [PATCH 179/211] seatd: Change default log-level to info --- seatd/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index f6bad9b..f88e6c9 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { int readiness = -1; bool unlink_existing_socket = true; bool chown_socket = true; - enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; + enum libseat_log_level level = LIBSEAT_LOG_LEVEL_INFO; while ((c = getopt(argc, argv, "vhn:g:u:l:z")) != -1) { switch (c) { case 'n': From abcecbb53b35cfb449ce1793f98bfdee5e604a94 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:40:40 +0100 Subject: [PATCH 180/211] 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. --- meson.build | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 960c3b6..1070b55 100644 --- a/meson.build +++ b/meson.build @@ -121,8 +121,10 @@ 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() @@ -137,8 +139,8 @@ if get_option('libseat-logind') != 'disabled' endif if logind.found() - add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') - add_project_arguments('-DHAVE_@0@=1'.format(logind.name().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', @@ -152,7 +154,7 @@ 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 +163,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' @@ -174,6 +177,7 @@ lib = library( install: true, link_args: symbols_flag, link_depends: symbols_file, + c_args: libseat_c_args, ) install_headers('include/libseat.h') From 46c83972fe66b917032a832bb8e3309ac6783d7d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:41:52 +0100 Subject: [PATCH 181/211] 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. --- libseat/backend/seatd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 6e90713..f55efe6 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -634,6 +634,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}; @@ -662,6 +663,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis close(fd); exit(res); } else { + close(fds[0]); int fd = fds[1]; return _open_seat(listener, data, fd); } From 795cf169e779aa003a5f4e990d7c9d307132d570 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:43:13 +0100 Subject: [PATCH 182/211] 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. --- seatd/client.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/seatd/client.c b/seatd/client.c index 220c5d3..6b6f3b3 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -81,6 +81,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); From 8dc6a50d88dcabda3f35135eacf075d5f4a18281 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:44:06 +0100 Subject: [PATCH 183/211] builtin: Remove deathsig and log start/stop Proper handling of client disconnect mean that we no longer need deathsig handling. --- libseat/backend/seatd.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index f55efe6..abcd2a5 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -600,25 +600,6 @@ const struct seat_impl seatd_impl = { }; #ifdef BUILTIN_ENABLED -#include - -static int set_deathsig(int signal); - -#if defined(__linux__) -#include - -static int set_deathsig(int signal) { - return prctl(PR_SET_PDEATHSIG, signal); -} -#elif defined(__FreeBSD__) -#include - -static int set_deathsig(int signal) { - return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signal); -} -#else -#error Unsupported platform -#endif static struct libseat *builtin_open_seat(const struct libseat_seat_listener *listener, void *data) { int fds[2]; @@ -649,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)); @@ -661,6 +642,7 @@ 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]); From ce6a6b7d2eb84fc2eb72ef97f7102012668b17e4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 17:52:26 +0100 Subject: [PATCH 184/211] meson: Fix meson warnings --- meson.build | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1070b55..9022dcd 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,12 @@ add_project_arguments(cc.get_supported_arguments( '-Wno-unknown-warning-option', '-Wno-unused-command-line-argument', '-Wvla', + ]), + language: 'c', +) + +add_project_arguments(cc.get_supported_link_arguments( + [ '-Wl,--exclude-libs=ALL', ]), language: 'c', @@ -66,7 +72,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 From bb0efb65b3894e42ab86e212cfa747f5348d4f2c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 17:52:50 +0100 Subject: [PATCH 185/211] Bump version to 0.7.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9022dcd..e6e583d 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.3', + version: '0.7.0', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 1990f9b0348412a06acae0e7d17d746905cc75b1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 16 Mar 2022 21:27:05 +0100 Subject: [PATCH 186/211] ci: Set loglevel argument to debug --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index bb8904a..7e59203 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -20,7 +20,7 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s sudo 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: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index da300c8..185d232 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -19,7 +19,7 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s sudo 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: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index b4bc7da..c8f9618 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -15,6 +15,6 @@ tasks: meson -Db_lundef=false -Db_sanitize=address -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled -Dlibseat-logind=disabled build seatd ninja -C build sudo ninja -C build install - timeout -s KILL 30s sudo 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 From 4ad48cb305b3f847ab7d3c2d3f59c27007519c77 Mon Sep 17 00:00:00 2001 From: illiliti Date: Fri, 4 Mar 2022 06:10:27 +0300 Subject: [PATCH 187/211] Initial netbsd support --- common/drm.c | 15 +++++++++++++++ common/evdev.c | 23 +++++++++++++++++++++++ common/terminal.c | 18 ++++++++++++++++-- include/drm.h | 2 +- include/evdev.h | 2 +- meson.build | 1 + seatd/client.c | 27 +++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 4 deletions(-) diff --git a/common/drm.c b/common/drm.c index 9591dc0..0d8096a 100644 --- a/common/drm.c +++ b/common/drm.c @@ -6,6 +6,11 @@ #include #endif +#if defined(__NetBSD__) +#include +#include +#endif + #include "drm.h" // From libdrm @@ -40,6 +45,16 @@ int path_is_drm(const char *path) { static const int prefixlen = STRLEN(prefix); return strncmp(prefix, path, prefixlen) == 0; } +#elif defined(__NetBSD__) +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) == getdevmajor("drm", S_IFCHR); +} #else #error Unsupported platform #endif diff --git a/common/evdev.c b/common/evdev.c index 4aff9bc..d2398fb 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -9,6 +9,9 @@ #include #elif defined(__FreeBSD__) #include +#elif defined(__NetBSD__) +#include +#include #else #error Unsupported platform #endif @@ -17,6 +20,7 @@ #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 +30,28 @@ int path_is_evdev(const char *path) { int evdev_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } +#endif #if defined(__linux__) int dev_is_evdev(dev_t device) { return major(device) == INPUT_MAJOR; } +#elif defined(__NetBSD__) +int dev_is_evdev(dev_t device) { + return major(device) == getdevmajor("wskbd", S_IFCHR) || + major(device) == getdevmajor("wsmouse", S_IFCHR) || + major(device) == getdevmajor("wsmux", S_IFCHR); +} +int path_is_evdev(const char *path) { + const char *wskbd = "/dev/wskbd"; + const char *wsmouse = "/dev/wsmouse"; + const char *wsmux = "/dev/wsmux"; + return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || + strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || + strncmp(path, wsmux, STRLEN(wsmouse)) == 0; +} +int evdev_revoke(int fd) { + (void)fd; + return 0; +} #endif diff --git a/common/terminal.c b/common/terminal.c index 0c3466f..183c9bd 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,6 +21,11 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO +#elif defined(__NetBSD__) +#include +#define K_ENABLE K_XLATE +#define K_DISABLE K_RAW +#define FRSIG 0 // unimplemented #else #error Unsupported platform #endif @@ -134,6 +139,14 @@ 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; +} #else #error Unsupported platform #endif @@ -153,7 +166,7 @@ int terminal_open(int vt) { } int terminal_current_vt(int fd) { -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) struct vt_stat st; int res = ioctl(fd, VT_GETSTATE, &st); close(fd); @@ -231,12 +244,13 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("Setting KD keyboard state to %d", enable); +#if defined(__linux__) || defined(__NetBSD__) 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; } -#if defined(__FreeBSD__) +#elif defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { log_errorf("Could not set get terminal mode: %s", strerror(errno)); diff --git a/include/drm.h b/include/drm.h index 8a7fb10..c8c3eeb 100644 --- a/include/drm.h +++ b/include/drm.h @@ -5,7 +5,7 @@ int drm_set_master(int fd); int drm_drop_master(int fd); int path_is_drm(const char *path); -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) #include int dev_is_drm(dev_t device); #endif diff --git a/include/evdev.h b/include/evdev.h index 6ebd943..da57828 100644 --- a/include/evdev.h +++ b/include/evdev.h @@ -4,7 +4,7 @@ int evdev_revoke(int fd); int path_is_evdev(const char *path); -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) #include int dev_is_evdev(dev_t device); #endif diff --git a/meson.build b/meson.build index e6e583d..0f267a6 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,7 @@ add_project_arguments( [ '-D_XOPEN_SOURCE=700', '-D__BSD_VISIBLE', + '-D_NETBSD_SOURCE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), diff --git a/seatd/client.c b/seatd/client.c index 6b6f3b3..0097792 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -14,6 +14,10 @@ #include #endif +#if defined(__NetBSD__) +#include +#endif + #include "client.h" #include "linked_list.h" #include "log.h" @@ -34,6 +38,23 @@ 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(__FreeBSD__) struct xucred cred; socklen_t len = sizeof cred; @@ -468,7 +489,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; } From a5f9a2a2c86abb7163d8f2c7fc34490dd6d26f29 Mon Sep 17 00:00:00 2001 From: illiliti Date: Fri, 4 Mar 2022 06:10:28 +0300 Subject: [PATCH 188/211] ci: Add NetBSD --- .builds/netbsd.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .builds/netbsd.yml diff --git a/.builds/netbsd.yml b/.builds/netbsd.yml new file mode 100644 index 0000000..a676138 --- /dev/null +++ b/.builds/netbsd.yml @@ -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 From 845256009b0ef7fcf9d59ceaf769cc5e41200c15 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 23 Mar 2022 20:29:09 +0100 Subject: [PATCH 189/211] readme: Mention NetBSD --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ed6e8b..b8a705f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A minimal seat management daemon, and a universal seat management library. -Currently supports Linux and FreeBSD. +Currently supports Linux and FreeBSD, and has experimental NetBSD support. ## What is seat management? From d5539dead8f258390c90e27acdc9f60a0cc68f2a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 28 Mar 2022 16:28:00 +0200 Subject: [PATCH 190/211] 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. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0f267a6..337a4ae 100644 --- a/meson.build +++ b/meson.build @@ -178,7 +178,7 @@ 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, From 684dd619455011bc08c85ae4c1b39394268b5646 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 29 Mar 2022 09:54:06 +0200 Subject: [PATCH 191/211] terminal: Revert FreeBSD behavior in set_keyboard 4ad48cb305b3f847ab7d3c2d3f59c27007519c77 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. --- common/terminal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 183c9bd..fa220a2 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -244,13 +244,12 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("Setting KD keyboard state to %d", enable); -#if defined(__linux__) || defined(__NetBSD__) 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; } -#elif defined(__FreeBSD__) +#if defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { log_errorf("Could not set get terminal mode: %s", strerror(errno)); From 0462e9331d1648171bd47e62a2808f0a4d647239 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 29 Mar 2022 10:41:16 +0200 Subject: [PATCH 192/211] wscons: Move to its own device type This reduces ifdefs and avoids overloading evdev as something it is not. --- common/evdev.c | 26 ++++---------------------- common/wscons.c | 27 +++++++++++++++++++++++++++ include/evdev.h | 5 ----- include/seat.h | 1 + include/wscons.h | 6 ++++++ meson.build | 1 + seatd/seat.c | 12 ++++++++++++ 7 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 common/wscons.c create mode 100644 include/wscons.h diff --git a/common/evdev.c b/common/evdev.c index d2398fb..7ec0fe2 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -9,11 +9,6 @@ #include #elif defined(__FreeBSD__) #include -#elif defined(__NetBSD__) -#include -#include -#else -#error Unsupported platform #endif #include "evdev.h" @@ -30,28 +25,15 @@ int path_is_evdev(const char *path) { int evdev_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } -#endif - -#if defined(__linux__) -int dev_is_evdev(dev_t device) { - return major(device) == INPUT_MAJOR; -} #elif defined(__NetBSD__) -int dev_is_evdev(dev_t device) { - return major(device) == getdevmajor("wskbd", S_IFCHR) || - major(device) == getdevmajor("wsmouse", S_IFCHR) || - major(device) == getdevmajor("wsmux", S_IFCHR); -} int path_is_evdev(const char *path) { - const char *wskbd = "/dev/wskbd"; - const char *wsmouse = "/dev/wsmouse"; - const char *wsmux = "/dev/wsmux"; - return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || - strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || - strncmp(path, wsmux, STRLEN(wsmouse)) == 0; + (void)path; + return 0; } int evdev_revoke(int fd) { (void)fd; return 0; } +#else +#error Unsupported platform #endif diff --git a/common/wscons.c b/common/wscons.c new file mode 100644 index 0000000..7fc8df5 --- /dev/null +++ b/common/wscons.c @@ -0,0 +1,27 @@ +#include +#include + +#if defined(__NetBSD__) +#include +#include +#endif + +#include "wscons.h" + +#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) + +#if defined(__NetBSD__) +int path_is_wscons(const char *path) { + const char *wskbd = "/dev/wskbd"; + const char *wsmouse = "/dev/wsmouse"; + const char *wsmux = "/dev/wsmux"; + return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || + strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || + strncmp(path, wsmux, STRLEN(wsmouse)) == 0; +} +#else +int path_is_wscons(const char *path) { + (void)path; + return 0; +} +#endif diff --git a/include/evdev.h b/include/evdev.h index da57828..5e6cfbf 100644 --- a/include/evdev.h +++ b/include/evdev.h @@ -4,9 +4,4 @@ int evdev_revoke(int fd); int path_is_evdev(const char *path); -#if defined(__linux__) || defined(__NetBSD__) -#include -int dev_is_evdev(dev_t device); -#endif - #endif diff --git a/include/seat.h b/include/seat.h index cc243b6..ff857e7 100644 --- a/include/seat.h +++ b/include/seat.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 { diff --git a/include/wscons.h b/include/wscons.h new file mode 100644 index 0000000..bf0c10c --- /dev/null +++ b/include/wscons.h @@ -0,0 +1,6 @@ +#ifndef _SEATD_WSCONS_H +#define _SEATD_WSCONS_H + +int path_is_wscons(const char *path); + +#endif diff --git a/meson.build b/meson.build index 337a4ae..661b39a 100644 --- a/meson.build +++ b/meson.build @@ -114,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', diff --git a/seatd/seat.c b/seatd/seat.c index 354273f..7a66a20 100644 --- a/seatd/seat.c +++ b/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); @@ -235,6 +236,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 +284,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 +339,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 +391,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(); From 8f8c9558e6279060f3ccc3363cb3558ffc9efd84 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 29 Mar 2022 10:46:09 +0200 Subject: [PATCH 193/211] 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. --- common/drm.c | 25 +------------------------ include/drm.h | 5 ----- libseat/backend/logind.c | 12 ++++++++++-- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/common/drm.c b/common/drm.c index 0d8096a..45ed7e5 100644 --- a/common/drm.c +++ b/common/drm.c @@ -2,15 +2,6 @@ #include #include -#if defined(__linux__) -#include -#endif - -#if defined(__NetBSD__) -#include -#include -#endif - #include "drm.h" // From libdrm @@ -29,32 +20,18 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) 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; -} #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; } -#elif defined(__NetBSD__) -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) == getdevmajor("drm", S_IFCHR); -} #else #error Unsupported platform #endif diff --git a/include/drm.h b/include/drm.h index c8c3eeb..a8a5461 100644 --- a/include/drm.h +++ b/include/drm.h @@ -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__) || defined(__NetBSD__) -#include -int dev_is_drm(dev_t device); -#endif - #endif diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 53523c8..2589e2f 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -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; @@ -387,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); @@ -419,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); From 85d0bf594362bf5d85b191711e6fc2a51f6bd21a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:27:39 +0000 Subject: [PATCH 194/211] seatd: handle client_create failure Failure to create the client causes a null pointer dereference. --- seatd/server.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/seatd/server.c b/seatd/server.c index 8ead54d..47d6e91 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -129,6 +129,12 @@ int server_add_client(struct server *server, int fd) { } 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) { From 2842f0e2b1eef5b648c76a8ae0ecbf8590bc873d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:27:40 +0000 Subject: [PATCH 195/211] 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. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 0097792..a33bfe7 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -70,7 +70,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 } From 6888653a8dd7e0a3124f3b7f1e3356ae9dc782e9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 30 Mar 2022 00:39:35 +0200 Subject: [PATCH 196/211] wscons: Fix STRLEN --- common/wscons.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/wscons.c b/common/wscons.c index 7fc8df5..33c757e 100644 --- a/common/wscons.c +++ b/common/wscons.c @@ -12,9 +12,9 @@ #if defined(__NetBSD__) int path_is_wscons(const char *path) { - const char *wskbd = "/dev/wskbd"; - const char *wsmouse = "/dev/wsmouse"; - const char *wsmux = "/dev/wsmux"; + 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; From a803ba0502cccf147eec7fbcacd11c5b8643c0e0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 May 2022 22:03:38 +0200 Subject: [PATCH 197/211] seatd-launch: Avoid argv[0] in help text --- seatd-launch/seatd-launch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 329ccef..65d4f33 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -33,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(); From 14355639f8a31e8a8b1d46fddcddfa924aa5f426 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Sep 2022 12:25:37 +0000 Subject: [PATCH 198/211] man: document SEATD_VTBOUND --- man/seatd.1.scd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index f599a23..48e3f64 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -41,6 +41,11 @@ client-side of the protocol. The location of the socket for seatd is set at compile-time. +# ENVIRONMENT + +*SEATD_VTBOUND* + If set to "0", the seat will not be bound to a VT. + # SEE ALSO The libseat library, **, *seatd-launch*(1) From 9b8b6e0bf88f02b77835c977ca97017ac6ed850f Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Fri, 13 Jan 2023 11:03:43 -0800 Subject: [PATCH 199/211] noop: initialize initial_setup Otherwise the enable_seat callback is never called. --- libseat/backend/noop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index f69aac6..7db8a55 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -115,6 +115,7 @@ static struct libseat *noop_open_seat(const struct libseat_seat_listener *listen return NULL; } + backend->initial_setup = true; backend->seat_listener = listener; backend->seat_listener_data = data; backend->base.impl = &noop_impl; From 207e2a59363037c192278bc51e3693d88d115514 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 Jan 2023 11:43:46 +0000 Subject: [PATCH 200/211] man: add missing arg in -n syntax --- man/seatd.1.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 48e3f64..92f8e4b 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -13,7 +13,7 @@ seatd - A seat management daemon *-h* Show help message and quit. -*-n* +*-n * FD to notify readiness on. A single newline will be written and the fd closed when seatd is ready to serve requests. This is compatible with s6's notification protocol. From 3e0d510b2c46eb18ab7239b029e01475eb2e3810 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sat, 11 Mar 2023 13:56:57 +0000 Subject: [PATCH 201/211] 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. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 661b39a..0c6c823 100644 --- a/meson.build +++ b/meson.build @@ -22,7 +22,7 @@ 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') From e5b018def8a672cf099df4270e9f3f224b51c09b Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Thu, 30 Mar 2023 07:58:49 -0300 Subject: [PATCH 202/211] 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 --- libseat/backend/noop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 7db8a55..141ffd9 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -46,7 +46,7 @@ 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) { From 56720a6275032ebafc4aed53d03612e5cc9d8ff7 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Thu, 30 Mar 2023 07:58:51 -0300 Subject: [PATCH 203/211] 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 --- libseat/backend/noop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 141ffd9..18f26c3 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -52,7 +52,7 @@ static const char *seat_name(struct libseat *base) { 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; From 1bd042e5b0a524fb7d30953179474e60974aa6ee Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Tue, 23 May 2023 21:31:21 +0100 Subject: [PATCH 204/211] 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. --- common/drm.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/common/drm.c b/common/drm.c index 45ed7e5..06d6720 100644 --- a/common/drm.c +++ b/common/drm.c @@ -10,7 +10,8 @@ #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); @@ -22,15 +23,18 @@ int drm_drop_master(int fd) { #if defined(__linux__) || defined(__NetBSD__) 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; + 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 From dbaa859f2899442909ece685634bb16d37f6a2ce Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:47:06 +0200 Subject: [PATCH 205/211] 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 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0c6c823..18aca69 100644 --- a/meson.build +++ b/meson.build @@ -29,7 +29,7 @@ cc = meson.get_compiler('c') add_project_arguments( [ '-D_XOPEN_SOURCE=700', - '-D__BSD_VISIBLE', + '-D_BSD_SOURCE', '-D_NETBSD_SOURCE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), From f2ff233c264a6332522c2aa05259b913e2e4af4b Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:48:14 +0200 Subject: [PATCH 206/211] No -lrt on OpenBSD XXX This is crude, should add meson tests --- meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 18aca69..36665de 100644 --- a/meson.build +++ b/meson.build @@ -158,8 +158,8 @@ if get_option('libseat-logind') != 'disabled' endif # needed for cross-compilation -realtime = meson.get_compiler('c').find_library('rt') -private_deps += realtime +# realtime = meson.get_compiler('c').find_library('rt') +# private_deps += realtime if with_builtin libseat_c_args += '-DBUILTIN_ENABLED=1' @@ -220,14 +220,14 @@ if with_server [ 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 From 4b2ecdf936366c79f3c58ef09dee3d87ccca88a8 Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:49:24 +0200 Subject: [PATCH 207/211] Add basic OpenBSD support XXX more work needed to manage VT switches and proper XXX fbtab(4) support to allow for non-root users --- common/drm.c | 2 +- common/evdev.c | 2 +- common/terminal.c | 12 ++++++++++-- seatd/client.c | 17 +++++++++++++++++ tests/poller.c | 4 ++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/common/drm.c b/common/drm.c index 06d6720..2fbadd5 100644 --- a/common/drm.c +++ b/common/drm.c @@ -21,7 +21,7 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -#if defined(__linux__) || defined(__NetBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) int path_is_drm(const char *path) { if (STR_HAS_PREFIX("/dev/dri/", path)) return 1; diff --git a/common/evdev.c b/common/evdev.c index 7ec0fe2..a77bf36 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -25,7 +25,7 @@ int path_is_evdev(const char *path) { int evdev_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) int path_is_evdev(const char *path) { (void)path; return 0; diff --git a/common/terminal.c b/common/terminal.c index fa220a2..7c1342e 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,7 +21,7 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) #include #define K_ENABLE K_XLATE #define K_DISABLE K_RAW @@ -147,6 +147,14 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { } 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 @@ -175,7 +183,7 @@ int terminal_current_vt(int fd) { return -1; } return st.v_active; -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) int vt; int res = ioctl(fd, VT_GETACTIVE, &vt); close(fd); diff --git a/seatd/client.c b/seatd/client.c index a33bfe7..0ab16f8 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -55,6 +55,23 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { *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; diff --git a/tests/poller.c b/tests/poller.c index 382d9d2..dd36c7d 100644 --- a/tests/poller.c +++ b/tests/poller.c @@ -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); From a8aee6fa70f68d54fe5f8a0db935cf85e83f849e Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:49:24 +0200 Subject: [PATCH 208/211] Add basic OpenBSD support XXX more work needed to manage VT switches and proper XXX fbtab(4) support to allow for non-root users --- common/wscons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/wscons.c b/common/wscons.c index 33c757e..121074c 100644 --- a/common/wscons.c +++ b/common/wscons.c @@ -10,7 +10,7 @@ #define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) -#if defined(__NetBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) int path_is_wscons(const char *path) { static const char wskbd[] = "/dev/wskbd"; static const char wsmouse[] = "/dev/wsmouse"; From 3e9ef69f14f630a719dd464f3c90a7932f1c8296 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 19 Jul 2023 11:18:33 +0200 Subject: [PATCH 209/211] Bump version to 0.8.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0c6c823..516d7d2 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.7.0', + version: '0.8.0', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 0746edbeaeb1c94a54bf833f6167b4a6b8237cbf Mon Sep 17 00:00:00 2001 From: Adrien Demarez Date: Tue, 24 Oct 2023 00:42:37 +0200 Subject: [PATCH 210/211] seatd: fix small bug in assert --- seatd/seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/seat.c b/seatd/seat.c index 7a66a20..d09b2eb 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -537,7 +537,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 From b4462cb033ad3172e6daa98a4eff2883f88ea524 Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 10 Jul 2024 15:19:41 +0200 Subject: [PATCH 211/211] attempt to support VT switches on OpenBSD --- common/terminal.c | 36 +++++++++++++++++++++++++++++++++--- seatd/client.c | 3 ++- seatd/seat.c | 3 ++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 7c1342e..5aac2dd 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,11 +21,17 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO -#elif defined(__NetBSD__) || defined(__OpenBSD__) +#elif defined(__NetBSD__) #include #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG 0 // unimplemented +#elif defined(__OpenBSD__) +#include +#include +#define K_ENABLE K_XLATE +#define K_DISABLE K_RAW +#define FRSIG SIGIO #else #error Unsupported platform #endif @@ -161,10 +167,16 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { 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)); @@ -174,7 +186,7 @@ int terminal_open(int vt) { } int terminal_current_vt(int fd) { -#if defined(__linux__) || defined(__NetBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) struct vt_stat st; int res = ioctl(fd, VT_GETSTATE, &st); close(fd); @@ -183,7 +195,7 @@ int terminal_current_vt(int fd) { return -1; } return st.v_active; -#elif defined(__FreeBSD__) || defined(__OpenBSD__) +#elif defined(__FreeBSD__) int vt; int res = ioctl(fd, VT_GETACTIVE, &vt); close(fd); @@ -252,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) { @@ -279,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; } diff --git a/seatd/client.c b/seatd/client.c index 0ab16f8..481704e 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -327,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; } @@ -370,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) { diff --git a/seatd/seat.c b/seatd/seat.c index d09b2eb..8820992 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -87,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; } @@ -107,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;