diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/backend.h | 32 | ||||
-rw-r--r-- | include/client.h | 37 | ||||
-rw-r--r-- | include/compiler.h | 18 | ||||
-rw-r--r-- | include/connection.h | 36 | ||||
-rw-r--r-- | include/drm.h | 10 | ||||
-rw-r--r-- | include/evdev.h | 9 | ||||
-rw-r--r-- | include/libseat.h | 140 | ||||
-rw-r--r-- | include/list.h | 22 | ||||
-rw-r--r-- | include/log.h | 51 | ||||
-rw-r--r-- | include/poller.h | 137 | ||||
-rw-r--r-- | include/protocol.h | 64 | ||||
-rw-r--r-- | include/seat.h | 47 | ||||
-rw-r--r-- | include/server.h | 26 | ||||
-rw-r--r-- | include/terminal.h | 14 |
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 |