aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorKenny Levinsen <kl@kl.wtf>2020-07-31 00:22:18 +0200
committerKenny Levinsen <kl@kl.wtf>2020-07-31 00:22:18 +0200
commit61716a2c77dfde9addf6b41a6d72d26a8584150e (patch)
tree537cd84661955497bdb304f88896e36896df4e5f /include
parentf85434de666f10da0cbcaccdbb7d88917c5fa887 (diff)
Initial implementation of seatd and libseat
Diffstat (limited to 'include')
-rw-r--r--include/backend.h32
-rw-r--r--include/client.h37
-rw-r--r--include/compiler.h18
-rw-r--r--include/connection.h36
-rw-r--r--include/drm.h10
-rw-r--r--include/evdev.h9
-rw-r--r--include/libseat.h140
-rw-r--r--include/list.h22
-rw-r--r--include/log.h51
-rw-r--r--include/poller.h137
-rw-r--r--include/protocol.h64
-rw-r--r--include/seat.h47
-rw-r--r--include/server.h26
-rw-r--r--include/terminal.h14
14 files changed, 643 insertions, 0 deletions
diff --git a/include/backend.h b/include/backend.h
new file mode 100644
index 0000000..e310a49
--- /dev/null
+++ b/include/backend.h
@@ -0,0 +1,32 @@
+#ifndef _SEATD_BACKEND_H
+#define _SEATD_BACKEND_H
+
+#include "libseat.h"
+
+struct libseat_impl;
+struct libseat_seat_listener;
+
+struct libseat {
+ const struct libseat_impl *impl;
+};
+
+struct named_backend {
+ const char *name;
+ const struct libseat_impl *backend;
+};
+
+struct libseat_impl {
+ struct libseat *(*open_seat)(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);
+
+ int (*open_device)(struct libseat *seat, const char *path, int *fd);
+ int (*close_device)(struct libseat *seat, int device_id);
+ int (*switch_session)(struct libseat *seat, int session);
+
+ int (*get_fd)(struct libseat *seat);
+ int (*dispatch)(struct libseat *seat, int timeout);
+};
+
+#endif
diff --git a/include/client.h b/include/client.h
new file mode 100644
index 0000000..6084980
--- /dev/null
+++ b/include/client.h
@@ -0,0 +1,37 @@
+#ifndef _SEATD_CLIENT_H
+#define _SEATD_CLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "connection.h"
+#include "list.h"
+
+struct server;
+
+struct client {
+ struct server *server;
+ struct event_source_fd *event_source;
+ struct connection connection;
+
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+
+ struct seat *seat;
+ int seat_vt;
+
+ struct list devices;
+};
+
+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);
+int client_get_session(struct client *client);
+int client_enable_seat(struct client *client);
+int client_disable_seat(struct client *client);
+
+#endif
diff --git a/include/compiler.h b/include/compiler.h
new file mode 100644
index 0000000..d0f6ed2
--- /dev/null
+++ b/include/compiler.h
@@ -0,0 +1,18 @@
+#ifndef _VISIBILITY_H
+#define _VISIBILITY_H
+
+#ifdef __GNUC__
+#define ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
+#else
+#define ATTRIB_PRINTF(start, end)
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define LIBSEAT_EXPORT __attribute__((visibility("default")))
+#define ALWAYS_INLINE __attribute__((always_inline)) inline
+#else
+#define LIBSEAT_EXPORT
+#define ALWAYS_INLINE inline
+#endif
+
+#endif
diff --git a/include/connection.h b/include/connection.h
new file mode 100644
index 0000000..6c57901
--- /dev/null
+++ b/include/connection.h
@@ -0,0 +1,36 @@
+#ifndef _SEATD_CONNECTION_H
+#define _SEATD_CONNECTION_H
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define CONNECTION_BUFFER_SIZE 1024
+
+#define MAX_FDS_OUT 8
+
+struct connection_buffer {
+ uint32_t head, tail;
+ char data[CONNECTION_BUFFER_SIZE];
+};
+
+struct connection {
+ struct connection_buffer in, out;
+ struct connection_buffer fds_in, fds_out;
+ int fd;
+ bool want_flush;
+};
+
+int connection_read(struct connection *connection);
+int connection_flush(struct connection *connection);
+
+int connection_put(struct connection *connection, const void *data, size_t count);
+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);
+void connection_restore(struct connection *connection, size_t count);
+
+void connection_close_fds(struct connection *connection);
+
+#endif
diff --git a/include/drm.h b/include/drm.h
new file mode 100644
index 0000000..1012c89
--- /dev/null
+++ b/include/drm.h
@@ -0,0 +1,10 @@
+#ifndef _SEATD_DRM_H
+#define _SEATD_DRM_H
+
+#include <sys/types.h>
+
+int drm_set_master(int fd);
+int drm_drop_master(int fd);
+int dev_is_drm(dev_t device);
+
+#endif
diff --git a/include/evdev.h b/include/evdev.h
new file mode 100644
index 0000000..0f20e3e
--- /dev/null
+++ b/include/evdev.h
@@ -0,0 +1,9 @@
+#ifndef _SEATD_EVDEV_H
+#define _SEATD_EVDEV_H
+
+#include <sys/types.h>
+
+int evdev_revoke(int fd);
+int dev_is_evdev(dev_t device);
+
+#endif
diff --git a/include/libseat.h b/include/libseat.h
new file mode 100644
index 0000000..7e9ef1f
--- /dev/null
+++ b/include/libseat.h
@@ -0,0 +1,140 @@
+#ifndef _LIBSEAT_H
+#define _LIBSEAT_H
+
+#include <stdarg.h>
+
+/*
+ * An opaque struct containing an opened seat, created by libseat_open-seat and
+ * destroyed by libseat_close_seat.
+ */
+struct libseat;
+
+/*
+ * A seat event listener, given to libseat_open_seat.
+ */
+struct libseat_seat_listener {
+ /*
+ * The seat has been enabled, and is now valid for use. Re-open all seat
+ * devices to ensure that they are operational, as existing fds may have
+ * had their functionality blocked or revoked.
+ *
+ * Must be non-NULL.
+ */
+ void (*enable_seat)(struct libseat *seat, void *userdata);
+
+ /*
+ * The seat has been disabled. This event signals that the application
+ * is going to lose its seat access. The event *must* be acknowledged
+ * with libseat_disable_seat shortly after receiving this event.
+ *
+ * If the recepient fails to acknowledge the event in time, seat devices
+ * may be forcibly revoked by the seat provider.
+ *
+ * Must be non-NULL.
+ */
+ void (*disable_seat)(struct libseat *seat, void *userdata);
+};
+
+/*
+ * Opens a seat, taking control of it if possible and returning a pointer to
+ * the libseat instance. If LIBSEAT_BACKEND is set, the specified backend is
+ * used. Otherwise, the first successful backend will be used.
+ *
+ * The seat listener specified is used to signal events on the seat, and must
+ * be non-NULL. The userdata pointer will be provided in all calls to the 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.
+ *
+ * The returned pointer must be destroyed with libseat_close_seat.
+ *
+ * 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);
+
+/*
+ * Disables a seat, used in response to a disable_seat event. After disabling
+ * the seat, the seat devices must not be used until enable_seat is received,
+ * and all requests on the seat will fail during this period.
+ *
+ * Returns 0 on success. -1 and sets errno on error.
+ */
+int libseat_disable_seat(struct libseat *seat);
+
+/*
+ * Closes the seat. This frees the libseat structure.
+ *
+ * Returns 0 on success. Returns -1 and sets errno on error.
+ */
+int libseat_close_seat(struct libseat *seat);
+
+/*
+ * Opens a device on the seat, returning its device ID and placing the fd in
+ * the specified pointer.
+ *
+ * This will only succeed if the seat is active and the device is of a type
+ * permitted for opening on the backend, such as drm and evdev.
+ *
+ * The device may be revoked in some situations, such as in situations where a
+ * seat session switch is being forced.
+ *
+ * Returns the device id on success. Returns -1 and sets errno on error.
+ */
+int libseat_open_device(struct libseat *seat, const char *path, int *fd);
+
+/*
+ * Closes a device that has been opened on the seat using the device_id from
+ * libseat_open_device.
+ *
+ * Returns 0 on success. Returns -1 and sets errno on error.
+ */
+int libseat_close_device(struct libseat *seat, int device_id);
+
+/*
+ * Retrieves the name of the seat that is currently made available through the
+ * provided libseat instance.
+ *
+ * The returned string is owned by the libseat instance, and must not be
+ * modified. It remains valid as long as the seat is open.
+ */
+const char *libseat_seat_name(struct libseat *seat);
+
+/*
+ * Requests that the seat switches session to the specified session number.
+ * For seats that are VT-bound, the session number matches the VT number, and
+ * switching session results in a VT switch.
+ *
+ * A call to libseat_switch_session does not imply that a switch will occur,
+ * and the caller should assume that the session continues unaffected.
+ *
+ * Returns 0 on success. Returns -1 and sets errno on error.
+ */
+int libseat_switch_session(struct libseat *seat, int session);
+
+/*
+ * Retrieve the pollable connection fd for a given libseat instance. Used to
+ * poll the libseat connection for events that need to be dispatched.
+ *
+ * Returns a pollable fd on success. Returns -1 and sets errno on error.
+ */
+int libseat_get_fd(struct libseat *seat);
+
+/*
+ * Reads and dispatches events on the libseat connection fd.
+ *
+ * The specified timeout dictates how long libseat might wait for data if none
+ * is available: 0 means that no wait will occur, -1 means that libseat might
+ * wait indefinitely for data to arrive, while > 0 is the maximum wait in
+ * 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.
+ */
+int libseat_dispatch(struct libseat *seat, int timeout);
+
+#endif
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 0000000..3f2ac6c
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,22 @@
+#ifndef _SEATD_LIST_H
+#define _SEATD_LIST_H
+
+#include <stddef.h>
+
+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, struct list *source);
+void list_truncate(struct list *list);
+void *list_pop_front(struct list *list);
+size_t list_find(struct list *list, const void *item);
+
+#endif
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..18a573e
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,51 @@
+#ifndef _LOG_H
+#define _LOG_H
+
+#include "compiler.h"
+#include <stdarg.h>
+
+enum libseat_log_level {
+ LIBSEAT_SILENT = 0,
+ LIBSEAT_ERROR = 1,
+ LIBSEAT_INFO = 2,
+ LIBSEAT_DEBUG = 3,
+ LIBSEAT_LOG_LEVEL_LAST,
+};
+
+void libseat_log_init(enum libseat_log_level level);
+
+void _libseat_logf(enum libseat_log_level level, const char *fmt, ...) ATTRIB_PRINTF(2, 3);
+
+#ifdef LIBSEAT_REL_SRC_DIR
+#define _LIBSEAT_FILENAME ((const char *)__FILE__ + sizeof(LIBSEAT_REL_SRC_DIR) - 1)
+#else
+#define _LIBSEAT_FILENAME __FILE__
+#endif
+
+#define log_infof(fmt, ...) \
+ _libseat_logf(LIBSEAT_INFO, "[%s:%d] %s: " fmt, _LIBSEAT_FILENAME, __LINE__, __func__, \
+ ##__VA_ARGS__)
+
+#define log_info(str) \
+ _libseat_logf(LIBSEAT_INFO, "[%s:%d] %s: %s", _LIBSEAT_FILENAME, __LINE__, __func__, str)
+
+#define log_errorf(fmt, ...) \
+ _libseat_logf(LIBSEAT_ERROR, "[%s:%d] %s: " fmt, _LIBSEAT_FILENAME, __LINE__, __func__, \
+ ##__VA_ARGS__)
+
+#define log_error(str) \
+ _libseat_logf(LIBSEAT_ERROR, "[%s:%d] %s: %s", _LIBSEAT_FILENAME, __LINE__, __func__, str)
+
+#ifdef DEBUG
+#define log_debugf(fmt, ...) \
+ _libseat_logf(LIBSEAT_DEBUG, "[%s:%d] %s: " fmt, _LIBSEAT_FILENAME, __LINE__, __func__, \
+ ##__VA_ARGS__)
+
+#define log_debug(str) \
+ _libseat_logf(LIBSEAT_DEBUG, "[%s:%d] %s: %s", _LIBSEAT_FILENAME, __LINE__, __func__, str)
+#else
+#define log_debugf(fmt, ...)
+#define log_debug(str)
+#endif
+
+#endif
diff --git a/include/poller.h b/include/poller.h
new file mode 100644
index 0000000..f867df9
--- /dev/null
+++ b/include/poller.h
@@ -0,0 +1,137 @@
+#ifndef _SEATD_POLLER_H
+#define _SEATD_POLLER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct poller;
+struct event_source_fd;
+struct event_source_signal;
+
+/*
+ * These are the event types available from the poller.
+ */
+#define EVENT_READABLE 0x1
+#define EVENT_WRITABLE 0x4
+#define EVENT_ERROR 0x8
+#define EVENT_HANGUP 0x10
+
+/**
+ * The callback type used by event_source_fd, passed to poller_add_fd.
+ */
+typedef int (*event_source_fd_func_t)(int fd, uint32_t mask, void *data);
+
+/**
+ * The interface that an event_source_fd must implement.
+ */
+struct event_source_fd_impl {
+ int (*update)(struct event_source_fd *event_source, uint32_t mask);
+ int (*destroy)(struct event_source_fd *event_source);
+};
+
+/**
+ * The fd poller base 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;
+};
+
+/**
+ * Removes the event_source_fd from the poller and frees the structure.
+ */
+int event_source_fd_destroy(struct event_source_fd *event_source);
+
+/**
+ * Updates the poll mask applied to this fd, effective on the next poll.
+ */
+int event_source_fd_update(struct event_source_fd *event_source, uint32_t mask);
+
+/**
+ * The callback type used by event_source_signal, passed to poller_add_signal.
+ */
+typedef int (*event_source_signal_func_t)(int signal, void *data);
+
+/**
+ * The interface that an event_source_signal must implement.
+ */
+struct event_source_signal_impl {
+ int (*destroy)(struct event_source_signal *event_source);
+};
+
+/*
+ * The signal poller base 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;
+};
+
+/**
+ * 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.
+ */
+struct poller {
+ const struct poll_impl *impl;
+};
+
+/**
+ * Creates a poller with the best available polling backend. This poller must
+ * be torn down with poller_destroy when it is no longer needed.
+ */
+struct poller *poller_create(void);
+
+/**
+ * Destroys the poller. This destroys all remaining event sources, tears down
+ * the poller and frees the structure.
+ */
+int poller_destroy(struct poller *poller);
+
+/**
+ * Create an fd event source with the provided initial parameters. This event
+ * source must be torn down with event_source_fd_destroy when it is no longer
+ * needed.
+ */
+struct event_source_fd *poller_add_fd(struct poller *poller, int fd, uint32_t mask,
+ event_source_fd_func_t func, void *data);
+
+/**
+ * Create signal event source with the provided initial parameters. This event
+ * source must be torn down with event_source_signal_destroy when it is no
+ * longer needed.
+ */
+struct event_source_signal *poller_add_signal(struct poller *poller, int signal,
+ event_source_signal_func_t func, void *data);
+
+/**
+ * Poll the poller. I don't know what you were expecting.
+ */
+int poller_poll(struct poller *poller);
+
+#endif
diff --git a/include/protocol.h b/include/protocol.h
new file mode 100644
index 0000000..7444b85
--- /dev/null
+++ b/include/protocol.h
@@ -0,0 +1,64 @@
+#ifndef _SEATD_CONSTANTS_H
+#define _SEATD_CONSTANTS_H
+
+#define MAX_PATH_LEN 256
+#define MAX_SEAT_LEN 64
+#define MAX_SEAT_DEVICES 128
+#define MAX_SESSION_LEN 64
+
+#define CLIENT_EVENT(opcode) (opcode)
+#define SERVER_EVENT(opcode) ((opcode) + (1 << 15))
+
+#define CLIENT_OPEN_SEAT CLIENT_EVENT(1)
+#define CLIENT_CLOSE_SEAT CLIENT_EVENT(2)
+#define CLIENT_OPEN_DEVICE CLIENT_EVENT(3)
+#define CLIENT_CLOSE_DEVICE CLIENT_EVENT(4)
+#define CLIENT_DISABLE_SEAT CLIENT_EVENT(5)
+#define CLIENT_SWITCH_SESSION CLIENT_EVENT(6)
+
+#define SERVER_SEAT_OPENED SERVER_EVENT(1)
+#define SERVER_SEAT_CLOSED SERVER_EVENT(2)
+#define SERVER_DEVICE_OPENED SERVER_EVENT(3)
+#define SERVER_DEVICE_CLOSED SERVER_EVENT(4)
+#define SERVER_DISABLE_SEAT SERVER_EVENT(5)
+#define SERVER_ENABLE_SEAT SERVER_EVENT(6)
+#define SERVER_ERROR SERVER_EVENT(0x7FFF)
+
+#include <stdint.h>
+
+struct proto_header {
+ uint16_t opcode;
+ uint16_t size;
+};
+
+struct proto_client_open_device {
+ uint16_t path_len;
+ // NULL-terminated byte-sequence path_len long follows
+};
+
+struct proto_client_close_device {
+ int device_id;
+};
+
+struct proto_client_switch_session {
+ int session;
+};
+
+struct proto_server_seat_opened {
+ uint16_t seat_name_len;
+ // NULL-terminated byte-sequence seat_name_len long follows
+};
+
+struct proto_server_device_opened {
+ int device_id;
+};
+
+struct proto_server_device_closed {
+ int device_id;
+};
+
+struct proto_server_error {
+ int error_code;
+};
+
+#endif
diff --git a/include/seat.h b/include/seat.h
new file mode 100644
index 0000000..e52a961
--- /dev/null
+++ b/include/seat.h
@@ -0,0 +1,47 @@
+#ifndef _SEATD_SEAT_H
+#define _SEATD_SEAT_H
+
+#include "list.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+struct client;
+
+struct seat_device {
+ int device_id;
+ int fd;
+ int ref_cnt;
+ bool active;
+ char *path;
+ dev_t dev;
+};
+
+struct seat {
+ char *seat_name;
+ struct list clients;
+ struct client *active_client;
+ struct client *next_client;
+
+ bool vt_bound;
+ bool vt_pending_ack;
+ int next_vt;
+};
+
+struct seat *seat_create(const char *name, bool vt_bound);
+void seat_destroy(struct seat *seat);
+
+int seat_add_client(struct seat *seat, struct client *client);
+int seat_remove_client(struct seat *seat, struct client *client);
+int seat_open_client(struct seat *seat, struct client *client);
+int seat_close_client(struct seat *seat, struct client *client);
+
+struct seat_device *seat_open_device(struct client *client, const char *path);
+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 seat *seat, int session);
+int seat_activate(struct seat *seat);
+int seat_prepare_vt_switch(struct seat *seat);
+
+#endif
diff --git a/include/server.h b/include/server.h
new file mode 100644
index 0000000..11de2c5
--- /dev/null
+++ b/include/server.h
@@ -0,0 +1,26 @@
+#ifndef _SEATD_SERVER_H
+#define _SEATD_SERVER_H
+
+#include <stdbool.h>
+
+#include "list.h"
+
+struct poller;
+struct client;
+
+struct server {
+ bool running;
+ struct poller *poller;
+
+ struct list seats;
+};
+
+struct server *server_create(void);
+void server_destroy(struct server *server);
+
+struct seat *server_get_seat(struct server *server, const char *seat_name);
+
+int server_listen(struct server *server, const char *path);
+int server_add_client(struct server *server, int fd);
+
+#endif
diff --git a/include/terminal.h b/include/terminal.h
new file mode 100644
index 0000000..c2a49ff
--- /dev/null
+++ b/include/terminal.h
@@ -0,0 +1,14 @@
+#ifndef _SEATD_TERMINAL_H
+#define _SEATD_TERMINAL_H
+
+#include <stdbool.h>
+
+int terminal_setup(int vt);
+int terminal_teardown(int vt);
+int terminal_current_vt(void);
+int terminal_switch_vt(int vt);
+int terminal_ack_switch(void);
+int terminal_set_keyboard(int vt, bool enable);
+int terminal_set_graphics(int vt, bool enable);
+
+#endif