From bcfb1d2ab5a2b5177c8d1ca2947fa80ce5d99803 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 23 Oct 2013 15:15:50 +0200 Subject: uvtd: remove Remove uvtd. The idea is outdated and not really needed. With recent systemd-logind changes, all we need is a shim between legacy-programs (like XServer) and logind. We can easily do that via libuvt without requiring a huge daemon like uvtd. Signed-off-by: David Herrmann --- src/uvtd_ctx.c | 474 ------------------------------------------ src/uvtd_ctx.h | 48 ----- src/uvtd_main.c | 276 ------------------------- src/uvtd_seat.c | 630 -------------------------------------------------------- src/uvtd_seat.h | 96 --------- src/uvtd_vt.c | 419 ------------------------------------- src/uvtd_vt.h | 54 ----- 7 files changed, 1997 deletions(-) delete mode 100644 src/uvtd_ctx.c delete mode 100644 src/uvtd_ctx.h delete mode 100644 src/uvtd_main.c delete mode 100644 src/uvtd_seat.c delete mode 100644 src/uvtd_seat.h delete mode 100644 src/uvtd_vt.c delete mode 100644 src/uvtd_vt.h (limited to 'src') diff --git a/src/uvtd_ctx.c b/src/uvtd_ctx.c deleted file mode 100644 index 20a9220..0000000 --- a/src/uvtd_ctx.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2012-2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Contexts - * A context manages a single UVT seat. It creates the seat object, allocates - * the VTs and provides all the bookkeeping for the sessions. It's the main - * entry point after the seat selectors in uvtd-main. - * - * For each seat we create two different kinds of character-devices: - * /dev/ttyFC: - * This is the control-node. It's the preferred way to open new VTs. It - * provides a fully-backwards compatible VT API so legacy apps should be - * able to make use of it. Each open-file is associated to a different VT so - * you cannot share these easily, anymore. You need to pass the FD instead. - * This avoids problems with multiple users on the same VT that we had in - * the past. - * /dev/ttyFD/tty: - * These are legacy VTs. They are put into a subdirectory and provide full - * backwards compatibility to real VTs. They are preallocated and there is - * only a limited number of them. You can control how many of these are - * allocated via the configuration options. - * These VTs can be shared between processes easily as all open-files on a - * single node share the same VT. - * All character devices share the MAJOR number that is also used by real VTs. - * However, the minor numbers use a relatively high offset (default: 2^14) so - * they don't clash with real VTs. - * If you need backwards-compatible symlinks, you can use the minor number of a - * VT node in /dev/ttyFD/tty and create a symlink: - * /dev/tty -> /dev/ttyFD/tty - * As the minors are globally unique, they won't clash with other tty nodes in - * /dev. However, you loose the ability to see which seat a node is associated - * to. So you normally look into /dev/ttyFD/, choose a node, look at the - * minor and then open /dev/tty respectively. - * This provides full backwards compatibility for applications that require - * /dev/tty paths (like old xservers). - * - * The VT logic is found in uvtd-vt subsystem. This file only provides the - * character-device control nodes and links them to the right VTs. - */ - -#include -#include -#include -#include -#include -#include -#include "eloop.h" -#include "shl_dlist.h" -#include "shl_log.h" -#include "uvt.h" -#include "uvtd_ctx.h" -#include "uvtd_seat.h" -#include "uvtd_vt.h" - -#define LOG_SUBSYSTEM "ctx" - -struct ctx_legacy { - struct shl_dlist list; - struct uvtd_ctx *ctx; - unsigned int minor; - unsigned int id; - struct uvt_cdev *cdev; - struct uvtd_vt *vt; -}; - -struct uvtd_ctx { - struct ev_eloop *eloop; - struct uvt_ctx *uctx; - struct uvtd_seat *seat; - char *seatname; - - unsigned int main_cdev_minor; - struct uvt_cdev *main_cdev; - - struct shl_dlist legacy_list; - unsigned int legacy_num; -}; - -static int ctx_legacy_init_vt(struct ctx_legacy *legacy); - -static void ctx_legacy_vt_event(void *vt, struct uvt_vt_event *ev, void *data) -{ - struct ctx_legacy *legacy = data; - - switch (ev->type) { - case UVT_VT_TTY: - if (ev->tty.type != UVT_TTY_HUP) - break; - - /* fallthrough */ - case UVT_VT_HUP: - log_debug("HUP on legacy VT %p", legacy); - - uvtd_vt_unregister_cb(legacy->vt, ctx_legacy_vt_event, legacy); - uvtd_vt_unref(legacy->vt); - legacy->vt = NULL; - break; - } -} - -static void ctx_legacy_cdev_event(struct uvt_cdev *cdev, - struct uvt_cdev_event *ev, void *data) -{ - struct ctx_legacy *legacy = data; - int ret; - - switch (ev->type) { - case UVT_CDEV_HUP: - log_warning("HUP on legacy cdev %p", cdev); - uvt_cdev_unregister_cb(legacy->cdev, ctx_legacy_cdev_event, - legacy); - uvt_cdev_unref(legacy->cdev); - legacy->cdev = NULL; - break; - case UVT_CDEV_OPEN: - /* A legacy VT might get closed by the seat/session-scheduler at - * any time. We want to avoid respawning it right away to avoid - * error-throttling, so instead we respawn it when the next - * client opens the underlying cdev. */ - if (!legacy->vt) { - log_debug("reinitializing VT on legacy cdev %p", - legacy); - ret = ctx_legacy_init_vt(legacy); - if (ret) { - log_warning("cannot reinitialize VT on legacy cdev %p", - legacy); - uvt_client_kill(ev->client); - break; - } - } - - ret = uvt_client_set_vt(ev->client, &uvtd_vt_ops, legacy->vt); - if (ret) { - log_warning("cannot assign VT to new client: %d", - ret); - uvt_client_kill(ev->client); - } - break; - } -} - -static int ctx_legacy_init_vt(struct ctx_legacy *legacy) -{ - int ret; - - ret = uvtd_vt_new(&legacy->vt, legacy->ctx->uctx, legacy->id, - legacy->ctx->seat, true); - if (ret) - return ret; - - ret = uvtd_vt_register_cb(legacy->vt, ctx_legacy_vt_event, legacy); - if (ret) { - uvtd_vt_unref(legacy->vt); - legacy->vt = NULL; - return ret; - } - - return 0; -} - -static int ctx_legacy_init_cdev(struct ctx_legacy *legacy) -{ - char *name; - int ret; - - ret = asprintf(&name, "ttyFD%s!tty%u", legacy->ctx->seatname, - legacy->minor); - if (ret <= 0) - return -ENOMEM; - - ret = uvt_cdev_new(&legacy->cdev, legacy->ctx->uctx, name, - uvt_ctx_get_major(legacy->ctx->uctx), - legacy->minor); - free(name); - - if (ret) - return ret; - - ret = uvt_cdev_register_cb(legacy->cdev, ctx_legacy_cdev_event, - legacy); - if (ret) { - uvt_cdev_unref(legacy->cdev); - legacy->cdev = NULL; - return ret; - } - - return 0; -} - -static int ctx_legacy_init(struct uvtd_ctx *ctx, unsigned int id) -{ - struct ctx_legacy *legacy; - int ret; - - legacy = malloc(sizeof(*legacy)); - if (!legacy) - return -ENOMEM; - - log_debug("new legacy cdev %p on ctx %p", legacy, ctx); - - memset(legacy, 0, sizeof(*legacy)); - legacy->id = id; - legacy->ctx = ctx; - - ret = uvt_ctx_new_minor(ctx->uctx, &legacy->minor); - if (ret) - goto err_free; - - ret = ctx_legacy_init_cdev(legacy); - if (ret) - goto err_minor; - - ret = ctx_legacy_init_vt(legacy); - if (ret) - goto err_cdev; - - shl_dlist_link(&ctx->legacy_list, &legacy->list); - return 0; - -err_cdev: - uvt_cdev_unregister_cb(legacy->cdev, ctx_legacy_cdev_event, legacy); - uvt_cdev_unref(legacy->cdev); -err_minor: - uvt_ctx_free_minor(ctx->uctx, legacy->minor); -err_free: - free(legacy); - return ret; -} - -static void ctx_legacy_destroy(struct ctx_legacy *legacy) -{ - log_debug("free legacy cdev %p", legacy); - - shl_dlist_unlink(&legacy->list); - uvtd_vt_unregister_cb(legacy->vt, ctx_legacy_vt_event, legacy); - uvtd_vt_unref(legacy->vt); - uvt_cdev_unregister_cb(legacy->cdev, ctx_legacy_cdev_event, legacy); - uvt_cdev_unref(legacy->cdev); - uvt_ctx_free_minor(legacy->ctx->uctx, legacy->minor); - free(legacy); -} - -static void ctx_legacy_reconf(struct uvtd_ctx *ctx, unsigned int num) -{ - struct ctx_legacy *l; - struct shl_dlist *iter; - unsigned int i; - int ret; - - /* If a legacy cdev received a HUP or some other error and got closed, - * we try to reinitialize it whenever the context is reconfigured. This - * avoids implementing any error-throttling while at the same time users - * can trigger a reinitialization with a reconfiguration. - * This doesn't touch running cdevs, but only HUP'ed cdevs. */ - shl_dlist_for_each(iter, &ctx->legacy_list) { - l = shl_dlist_entry(iter, struct ctx_legacy, list); - if (l->cdev) - continue; - - log_debug("reinitialize legacy cdev %p", l); - - ret = ctx_legacy_init_cdev(l); - if (ret) - log_warning("cannot reinitialize legacy cdev %p: %d", - l, ret); - } - - if (num == ctx->legacy_num) - return; - - log_debug("changing #num of legacy cdevs on ctx %p from %u to %u", - ctx, ctx->legacy_num, num); - - if (num > ctx->legacy_num) { - for (i = ctx->legacy_num; i < num; ++i) { - ret = ctx_legacy_init(ctx, i); - if (ret) - break; - } - - ctx->legacy_num = i; - } else { - for (i = num; i < ctx->legacy_num; ++i) { - l = shl_dlist_last(&ctx->legacy_list, - struct ctx_legacy, list); - ctx_legacy_destroy(l); - } - - ctx->legacy_num = num; - } -} - -static void ctx_main_cdev_event(struct uvt_cdev *cdev, - struct uvt_cdev_event *ev, - void *data) -{ - struct uvtd_ctx *ctx = data; - struct uvtd_vt *vt; - int ret; - - switch (ev->type) { - case UVT_CDEV_HUP: - log_warning("HUP on main cdev on ctx %p", ctx); - uvt_cdev_unregister_cb(ctx->main_cdev, ctx_main_cdev_event, - ctx); - uvt_cdev_unref(ctx->main_cdev); - ctx->main_cdev = NULL; - break; - case UVT_CDEV_OPEN: - ret = uvtd_vt_new(&vt, ctx->uctx, 0, ctx->seat, false); - if (ret) - break; - - uvt_client_set_vt(ev->client, &uvtd_vt_ops, vt); - uvtd_vt_unref(vt); - break; - } -} - -static int ctx_init_cdev(struct uvtd_ctx *ctx) -{ - int ret; - char *name; - - ret = asprintf(&name, "ttyFC%s", ctx->seatname); - if (ret <= 0) - return -ENOMEM; - - ret = uvt_cdev_new(&ctx->main_cdev, ctx->uctx, name, - uvt_ctx_get_major(ctx->uctx), ctx->main_cdev_minor); - free(name); - - if (ret) - return ret; - - ret = uvt_cdev_register_cb(ctx->main_cdev, ctx_main_cdev_event, ctx); - if (ret) { - uvt_cdev_unref(ctx->main_cdev); - ctx->main_cdev = NULL; - return ret; - } - - return 0; -} - -static bool has_real_vts(const char *seatname) -{ - return !strcmp(seatname, "seat0") && - !access("/dev/tty0", F_OK); -} - -int uvtd_ctx_new(struct uvtd_ctx **out, const char *seatname, - struct ev_eloop *eloop, struct uvt_ctx *uctx) -{ - struct uvtd_ctx *ctx; - int ret; - - if (!out || !seatname || !eloop || !uctx) - return -EINVAL; - - if (has_real_vts(seatname)) - return -EEXIST; - - ctx = malloc(sizeof(*ctx)); - if (!ctx) - return -ENOMEM; - - log_debug("new ctx %p on seat %s", ctx, seatname); - - memset(ctx, 0, sizeof(*ctx)); - ctx->eloop = eloop; - ctx->uctx = uctx; - shl_dlist_init(&ctx->legacy_list); - - ctx->seatname = strdup(seatname); - if (!ctx->seatname) { - ret = -ENOMEM; - goto err_free; - } - - ret = uvtd_seat_new(&ctx->seat, seatname, ctx->eloop, NULL, NULL); - if (ret) - goto err_name; - - ret = uvt_ctx_new_minor(ctx->uctx, &ctx->main_cdev_minor); - if (ret) - goto err_seat; - - ret = ctx_init_cdev(ctx); - if (ret) - goto err_minor; - - ev_eloop_ref(ctx->eloop); - uvt_ctx_ref(ctx->uctx); - *out = ctx; - - ctx_legacy_reconf(ctx, 8); - - return 0; - -err_minor: - uvt_ctx_free_minor(ctx->uctx, ctx->main_cdev_minor); -err_seat: - uvtd_seat_free(ctx->seat); -err_name: - free(ctx->seatname); -err_free: - free(ctx); - return ret; -} - -void uvtd_ctx_free(struct uvtd_ctx *ctx) -{ - if (!ctx) - return; - - log_debug("free ctx %p", ctx); - - ctx_legacy_reconf(ctx, 0); - uvt_cdev_unregister_cb(ctx->main_cdev, ctx_main_cdev_event, ctx); - uvt_cdev_unref(ctx->main_cdev); - uvt_ctx_free_minor(ctx->uctx, ctx->main_cdev_minor); - uvtd_seat_free(ctx->seat); - free(ctx->seatname); - uvt_ctx_unref(ctx->uctx); - ev_eloop_unref(ctx->eloop); - free(ctx); -} - -void uvtd_ctx_reconf(struct uvtd_ctx *ctx, unsigned int legacy_num) -{ - int ret; - - if (!ctx) - return; - - ctx_legacy_reconf(ctx, legacy_num); - - /* Lets recreate the control node if it got busted during runtime. We do - * not recreate it right away after receiving a HUP signal to avoid - * trapping into the same error that caused the HUP. - * Instead we recreate the node on reconfiguration so users can control - * when to recreate them. */ - if (!ctx->main_cdev) { - log_debug("recreating main cdev on ctx %p", ctx); - ret = ctx_init_cdev(ctx); - if (ret) - log_warning("cannot recreate main cdev on ctx %p", - ctx); - } -} diff --git a/src/uvtd_ctx.h b/src/uvtd_ctx.h deleted file mode 100644 index 78e3f0b..0000000 --- a/src/uvtd_ctx.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Contexts - * A context manages a single UVT seat. It creates the seat object, allocates - * the VTs and provides all the bookkeeping for the sessions. It's the main - * entry point after the seat selectors in uvtd-main. - */ - -#ifndef UVTD_CTX_H -#define UVTD_CTX_H - -#include -#include "eloop.h" -#include "uvt.h" - -struct uvtd_ctx; - -int uvtd_ctx_new(struct uvtd_ctx **out, const char *seatname, - struct ev_eloop *eloop, struct uvt_ctx *uctx); -void uvtd_ctx_free(struct uvtd_ctx *ctx); - -void uvtd_ctx_reconf(struct uvtd_ctx *ctx, unsigned int legacy_num); - -#endif /* UVTD_CTX_H */ diff --git a/src/uvtd_main.c b/src/uvtd_main.c deleted file mode 100644 index d4b70ff..0000000 --- a/src/uvtd_main.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2012-2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "eloop.h" -#include "shl_dlist.h" -#include "shl_log.h" -#include "uterm_input.h" -#include "uterm_monitor.h" -#include "uvt.h" -#include "uvtd_ctx.h" - -struct app_seat { - struct shl_dlist list; - struct uvtd_app *app; - struct uterm_monitor_seat *useat; - struct uvtd_ctx *ctx; -}; - -struct uvtd_app { - struct ev_eloop *eloop; - struct uterm_monitor *mon; - struct uvt_ctx *ctx; - struct ev_fd *ctx_fd; - struct shl_dlist seats; -}; - -static int app_seat_new(struct uvtd_app *app, const char *sname, - struct uterm_monitor_seat *useat) -{ - struct app_seat *seat; - int ret; - - seat = malloc(sizeof(*seat)); - if (!seat) - return -ENOMEM; - - log_debug("new seat %p on %s", seat, sname); - - memset(seat, 0, sizeof(*seat)); - seat->app = app; - seat->useat = useat; - - ret = uvtd_ctx_new(&seat->ctx, sname, app->eloop, app->ctx); - if (ret == -EEXIST) { - log_debug("ignoring seat %s as it has real VTs", sname); - goto err_free; - } else if (ret) { - goto err_free; - } - - uterm_monitor_set_seat_data(seat->useat, seat); - shl_dlist_link(&app->seats, &seat->list); - return 0; - -err_free: - free(seat); - return ret; -} - -static void app_seat_free(struct app_seat *seat) -{ - log_debug("free seat %p", seat); - - shl_dlist_unlink(&seat->list); - uterm_monitor_set_seat_data(seat->useat, NULL); - uvtd_ctx_free(seat->ctx); - free(seat); -} - -static void app_monitor_event(struct uterm_monitor *mon, - struct uterm_monitor_event *ev, - void *data) -{ - struct uvtd_app *app = data; - struct app_seat *seat; - int ret; - - switch (ev->type) { - case UTERM_MONITOR_NEW_SEAT: - ret = app_seat_new(app, ev->seat_name, ev->seat); - if (ret) - return; - break; - case UTERM_MONITOR_FREE_SEAT: - if (ev->seat_data) - app_seat_free(ev->seat_data); - break; - case UTERM_MONITOR_NEW_DEV: - seat = ev->seat_data; - if (!seat) - return; - - switch (ev->dev_type) { - case UTERM_MONITOR_INPUT: - log_debug("new input device %s on seat %p", - ev->dev_node, seat); - break; - } - break; - case UTERM_MONITOR_FREE_DEV: - seat = ev->seat_data; - if (!seat) - return; - - switch (ev->dev_type) { - case UTERM_MONITOR_INPUT: - log_debug("free input device %s on seat %p", - ev->dev_node, seat); - break; - } - break; - } -} - -static void app_sig_generic(struct ev_eloop *eloop, - struct signalfd_siginfo *info, - void *data) -{ - struct uvtd_app *app = data; - - log_info("terminating due to caught signal %d", info->ssi_signo); - ev_eloop_exit(app->eloop); -} - -static void app_sig_ignore(struct ev_eloop *eloop, - struct signalfd_siginfo *info, - void *data) -{ -} - -static void app_ctx_event(struct ev_fd *fd, int mask, void *data) -{ - struct uvtd_app *app = data; - - uvt_ctx_dispatch(app->ctx); - - if (!(mask & EV_READABLE) && mask & (EV_HUP | EV_ERR)) { - log_error("HUP on UVT ctx fd"); - ev_eloop_rm_fd(fd); - app->ctx_fd = NULL; - } -} - -static void destroy_app(struct uvtd_app *app) -{ - ev_eloop_rm_fd(app->ctx_fd); - uvt_ctx_unref(app->ctx); - uterm_monitor_unref(app->mon); - ev_eloop_unregister_signal_cb(app->eloop, SIGPIPE, app_sig_ignore, - app); - ev_eloop_unregister_signal_cb(app->eloop, SIGINT, app_sig_generic, - app); - ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, app_sig_generic, - app); - ev_eloop_unref(app->eloop); -} - -static int setup_app(struct uvtd_app *app) -{ - int ret, fd; - - shl_dlist_init(&app->seats); - - ret = ev_eloop_new(&app->eloop, log_llog, NULL); - if (ret) { - log_error("cannot create eloop object: %d", ret); - goto err_app; - } - - ret = ev_eloop_register_signal_cb(app->eloop, SIGTERM, - app_sig_generic, app); - if (ret) { - log_error("cannot register SIGTERM signal handler: %d", ret); - goto err_app; - } - - ret = ev_eloop_register_signal_cb(app->eloop, SIGINT, - app_sig_generic, app); - if (ret) { - log_error("cannot register SIGINT signal handler: %d", ret); - goto err_app; - } - - ret = ev_eloop_register_signal_cb(app->eloop, SIGPIPE, - app_sig_ignore, app); - if (ret) { - log_error("cannot register SIGPIPE signal handler: %d", ret); - goto err_app; - } - - ret = uterm_monitor_new(&app->mon, app->eloop, app_monitor_event, app); - if (ret) { - log_error("cannot create device monitor: %d", ret); - goto err_app; - } - - ret = uvt_ctx_new(&app->ctx, log_llog, NULL); - if (ret) { - log_error("cannot create UVT context: %d", ret); - goto err_app; - } - - fd = uvt_ctx_get_fd(app->ctx); - if (fd >= 0) { - ret = ev_eloop_new_fd(app->eloop, &app->ctx_fd, fd, - EV_READABLE, app_ctx_event, app); - if (ret) { - log_error("cannot create UVT ctx efd: %d", ret); - goto err_app; - } - } - - log_debug("scanning for devices..."); - uterm_monitor_scan(app->mon); - - return 0; - -err_app: - destroy_app(app); - return ret; -} - -int main(int argc, char **argv) -{ - int ret; - struct uvtd_app app; - - log_set_config(&LOG_CONFIG_INFO(1, 1)); - log_print_init("uvtd"); - - memset(&app, 0, sizeof(app)); - - ret = setup_app(&app); - if (ret) - goto err_out; - - ev_eloop_run(app.eloop, -1); - - ret = 0; - destroy_app(&app); -err_out: - if (ret) - log_err("cannot initialize uvtd, errno %d: %s", - ret, strerror(-ret)); - log_info("exiting"); - return -ret; -} diff --git a/src/uvtd_seat.c b/src/uvtd_seat.c deleted file mode 100644 index 0a1d71c..0000000 --- a/src/uvtd_seat.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2012-2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Seats - * Each set of input+output devices form a single seat. Each seat is independent - * of each other and there can be exactly one user per seat interacting with the - * system. - * Per seat, we have multiple sessions. But only one session can be active at a - * time per seat. We allow external sessions, so session activation/deactivation - * may be asynchronous. - * - * A seat object manages all the sessions for a single seat. As long as a seat - * is asleep, no session is active. If you wake it up, the seat manager - * automatically schedules a session. You can then request other sessions to be - * scheduled and the seat manager will try to deactivate the current session and - * reactivate the new session. - * - * Note that session deactivation may be asynchronous (unless forced). So some - * calls might return -EINPROGRESS if the session-deactivation is pending. This - * shouldn't bother the user as the session will notify back soon that the - * deactivation was successfull. However, if it doesn't the user can chose to - * perform any other action and we will retry the operation. As a last resort, - * you can always kill the session by unregistering it or forcing a - * deactivation. - * "async_schedule" tracks the task that requested the deactivation of a - * session. So when the session notifies us that it got deactivated, we know - * what the user wanted and can perform the requested task now. - */ - -#include -#include -#include -#include "eloop.h" -#include "shl_dlist.h" -#include "shl_log.h" -#include "uvtd_seat.h" - -#define LOG_SUBSYSTEM "seat" - -struct uvtd_session { - struct shl_dlist list; - unsigned long ref; - struct uvtd_seat *seat; - unsigned int id; - - bool enabled; - bool deactivating; - - uvtd_session_cb_t cb; - void *data; -}; - -/* task that requested the pending session-deactivation */ -enum uvtd_async_schedule { - SCHEDULE_NONE, /* default, causes a reschedule */ - SCHEDULE_SWITCH, /* causes a reschedule */ - SCHEDULE_SLEEP, /* puts the seat asleep */ - SCHEDULE_UNREGISTER, /* unregisters the session */ -}; - -struct uvtd_seat { - struct ev_eloop *eloop; - char *name; - - size_t session_count; - struct shl_dlist sessions; - - bool awake; - struct uvtd_session *current_sess; - struct uvtd_session *scheduled_sess; - struct uvtd_session *dummy_sess; - - unsigned int async_schedule; - - uvtd_seat_cb_t cb; - void *data; -}; - -static int session_call(struct uvtd_session *sess, unsigned int event) -{ - if (!sess->cb) - return 0; - - return sess->cb(sess, event, sess->data); -} - -static int session_call_activate(struct uvtd_session *sess) -{ - log_debug("activate session %p", sess); - return session_call(sess, UVTD_SESSION_ACTIVATE); -} - -static int session_call_deactivate(struct uvtd_session *sess) -{ - log_debug("deactivate session %p", sess); - return session_call(sess, UVTD_SESSION_DEACTIVATE); -} - -/* drop the current session as if it was successfully deactivated */ -static void seat_yield(struct uvtd_seat *seat) -{ - if (!seat->current_sess) - return; - - seat->current_sess->deactivating = false; - seat->current_sess = NULL; - seat->async_schedule = SCHEDULE_NONE; -} - -static int seat_go_asleep(struct uvtd_seat *seat, bool force) -{ - int ret = 0; - - if (!seat->awake) - return 0; - - if (seat->current_sess) { - ret = -EBUSY; - if (!force) - return ret; - - seat_yield(seat); - } - - seat->awake = false; - - if (seat->cb) - seat->cb(seat, UVTD_SEAT_SLEEP, seat->data); - - return ret; -} - -static void seat_go_awake(struct uvtd_seat *seat) -{ - if (seat->awake) - return; - - seat->awake = true; -} - -static int seat_run(struct uvtd_seat *seat) -{ - int ret; - struct uvtd_session *session; - - if (!seat->awake) - return -EBUSY; - if (seat->current_sess) - return 0; - - if (!seat->scheduled_sess) { - log_debug("no session scheduled to run (num: %zu)", - seat->session_count); - return -ENOENT; - } - session = seat->scheduled_sess; - - /* TODO: unregister session and try next on failure */ - ret = session_call_activate(session); - if (ret) { - log_warning("cannot activate session %p: %d", session, ret); - return ret; - } - - seat->current_sess = session; - - return 0; -} - -static int seat_pause(struct uvtd_seat *seat, bool force, unsigned int async) -{ - int ret; - - if (!seat->current_sess) - return 0; - - /* TODO: pass \force to the session */ - seat->current_sess->deactivating = true; - ret = session_call_deactivate(seat->current_sess); - if (ret) { - if (!force && ret == -EINPROGRESS) { - seat->async_schedule = async; - log_debug("pending deactivation for session %p", - seat->current_sess); - } else { - log_warning("cannot deactivate session %p (%d): %d", - seat->current_sess, force, ret); - } - - if (!force) - return ret; - } - - seat_yield(seat); - return ret; -} - -static void seat_reschedule(struct uvtd_seat *seat) -{ - struct shl_dlist *iter, *start; - struct uvtd_session *sess; - - if (seat->scheduled_sess && seat->scheduled_sess->enabled) - return; - - if (seat->current_sess && seat->current_sess->enabled) { - seat->scheduled_sess = seat->current_sess; - return; - } - - if (seat->current_sess) - start = &seat->current_sess->list; - else - start = &seat->sessions; - - shl_dlist_for_each_but_one(iter, start, &seat->sessions) { - sess = shl_dlist_entry(iter, struct uvtd_session, list); - - if (sess != seat->dummy_sess && sess->enabled) { - seat->scheduled_sess = sess; - return; - } - } - - if (seat->dummy_sess && seat->dummy_sess->enabled) - seat->scheduled_sess = seat->dummy_sess; - else - seat->scheduled_sess = NULL; -} - -static bool seat_has_schedule(struct uvtd_seat *seat) -{ - return seat->scheduled_sess && - seat->scheduled_sess != seat->current_sess; -} - -static int seat_switch(struct uvtd_seat *seat) -{ - int ret; - - ret = seat_pause(seat, false, SCHEDULE_SWITCH); - if (ret) - return ret; - - return seat_run(seat); -} - -static void seat_schedule(struct uvtd_seat *seat, struct uvtd_session *sess) -{ - seat->scheduled_sess = sess; - seat_reschedule(seat); - if (seat_has_schedule(seat)) - seat_switch(seat); -} - -static void seat_next(struct uvtd_seat *seat, bool reverse) -{ - struct shl_dlist *cur, *iter; - struct uvtd_session *s, *next; - - if (seat->current_sess) - cur = &seat->current_sess->list; - else if (seat->session_count) - cur = &seat->sessions; - else - return; - - next = NULL; - if (!seat->current_sess && seat->dummy_sess && - seat->dummy_sess->enabled) - next = seat->dummy_sess; - - if (reverse) { - shl_dlist_for_each_reverse_but_one(iter, cur, - &seat->sessions) { - s = shl_dlist_entry(iter, struct uvtd_session, list); - - if (s->enabled && seat->dummy_sess != s) { - next = s; - break; - } - } - } else { - shl_dlist_for_each_but_one(iter, cur, &seat->sessions) { - s = shl_dlist_entry(iter, struct uvtd_session, list); - - if (s->enabled && seat->dummy_sess != s) { - next = s; - break; - } - } - } - - if (!next) - return; - - seat_schedule(seat, next); -} - -int uvtd_seat_new(struct uvtd_seat **out, const char *seatname, - struct ev_eloop *eloop, uvtd_seat_cb_t cb, void *data) -{ - struct uvtd_seat *seat; - int ret; - - if (!out || !eloop || !seatname) - return -EINVAL; - - seat = malloc(sizeof(*seat)); - if (!seat) - return -ENOMEM; - memset(seat, 0, sizeof(*seat)); - seat->eloop = eloop; - seat->cb = cb; - seat->data = data; - shl_dlist_init(&seat->sessions); - - seat->name = strdup(seatname); - if (!seat->name) { - ret = -ENOMEM; - goto err_free; - } - - ev_eloop_ref(seat->eloop); - *out = seat; - return 0; - -err_free: - free(seat); - return ret; -} - -void uvtd_seat_free(struct uvtd_seat *seat) -{ - struct uvtd_session *s; - int ret; - - if (!seat) - return; - - ret = seat_pause(seat, true, SCHEDULE_NONE); - if (ret) - log_warning("destroying seat %s while session %p is active", - seat->name, seat->current_sess); - - ret = seat_go_asleep(seat, true); - if (ret) - log_warning("destroying seat %s while still awake: %d", - seat->name, ret); - - while (!shl_dlist_empty(&seat->sessions)) { - s = shl_dlist_entry(seat->sessions.next, struct uvtd_session, - list); - uvtd_session_unregister(s); - } - - free(seat->name); - ev_eloop_unref(seat->eloop); - free(seat); -} - -const char *uvtd_seat_get_name(struct uvtd_seat *seat) -{ - return seat ? seat->name : NULL; -} - -struct ev_eloop *uvtd_seat_get_eloop(struct uvtd_seat *seat) -{ - return seat ? seat->eloop : NULL; -} - -int uvtd_seat_sleep(struct uvtd_seat *seat, bool force) -{ - int ret, err = 0; - - if (!seat) - return -EINVAL; - - ret = seat_pause(seat, force, SCHEDULE_SLEEP); - if (ret) { - if (force) - err = ret; - else - return ret; - } - - ret = seat_go_asleep(seat, force); - if (ret) { - if (force) - err = ret; - else - return ret; - } - - return err; -} - -void uvtd_seat_wake_up(struct uvtd_seat *seat) -{ - if (!seat) - return; - - seat_go_awake(seat); - seat_run(seat); -} - -void uvtd_seat_schedule(struct uvtd_seat *seat, unsigned int id) -{ - struct shl_dlist *iter; - struct uvtd_session *session; - unsigned int i; - - if (!seat || !id) - return; - - session = NULL; - i = id; - shl_dlist_for_each(iter, &seat->sessions) { - session = shl_dlist_entry(iter, struct uvtd_session, list); - if (!--i) - break; - if (session->id >= id) - break; - } - - if (session) - seat_schedule(seat, session); -} - -int uvtd_seat_register_session(struct uvtd_seat *seat, - struct uvtd_session **out, - unsigned int id, uvtd_session_cb_t cb, - void *data) -{ - struct uvtd_session *sess, *s; - struct shl_dlist *iter; - - if (!seat || !out) - return -EINVAL; - - sess = malloc(sizeof(*sess)); - if (!sess) - return -ENOMEM; - - log_debug("register session %p with id %u on seat %p", - sess, id, seat); - - memset(sess, 0, sizeof(*sess)); - sess->ref = 1; - sess->seat = seat; - sess->cb = cb; - sess->data = data; - sess->id = id; - - ++seat->session_count; - *out = sess; - - if (sess->id) { - shl_dlist_for_each(iter, &seat->sessions) { - s = shl_dlist_entry(iter, struct uvtd_session, list); - if (!s->id || s->id > sess->id) { - shl_dlist_link_tail(iter, &sess->list); - return 0; - } - - if (s->id == sess->id) - log_warning("session %p shadowed by %p", - sess, s); - } - } - - shl_dlist_link_tail(&seat->sessions, &sess->list); - return 0; -} - -void uvtd_session_ref(struct uvtd_session *sess) -{ - if (!sess || !sess->ref) - return; - - ++sess->ref; -} - -void uvtd_session_unref(struct uvtd_session *sess) -{ - if (!sess || !sess->ref || --sess->ref) - return; - - uvtd_session_unregister(sess); - free(sess); -} - -void uvtd_session_unregister(struct uvtd_session *sess) -{ - struct uvtd_seat *seat; - int ret; - bool forced = false; - - if (!sess || !sess->seat) - return; - - log_debug("unregister session %p", sess); - - seat = sess->seat; - sess->enabled = false; - if (seat->dummy_sess == sess) - seat->dummy_sess = NULL; - seat_reschedule(seat); - - if (seat->current_sess == sess) { - ret = seat_pause(seat, true, SCHEDULE_NONE); - if (ret) { - forced = true; - log_warning("unregistering active session %p; skipping automatic session-switch", - sess); - } - } - - shl_dlist_unlink(&sess->list); - --seat->session_count; - sess->seat = NULL; - - session_call(sess, UVTD_SESSION_UNREGISTER); - uvtd_session_unref(sess); - - /* If this session was active and we couldn't deactivate it, then it - * might still have resources allocated that couldn't get freed. In this - * case we should not automatically switch to the next session as it is - * very likely that it will not be able to start. - * Instead, we stay inactive and wait for user/external input to switch - * to another session. This delay will then hopefully be long enough so - * all resources got freed. */ - if (!forced) - seat_run(seat); -} - -bool uvtd_session_is_registered(struct uvtd_session *sess) -{ - return sess && sess->seat; -} - -bool uvtd_session_is_active(struct uvtd_session *sess) -{ - return sess && sess->seat && sess->seat->current_sess == sess; -} - -void uvtd_session_schedule(struct uvtd_session *sess) -{ - if (!sess || !sess->seat) - return; - - seat_schedule(sess->seat, sess); -} - -void uvtd_session_enable(struct uvtd_session *sess) -{ - if (!sess || sess->enabled) - return; - - log_debug("enable session %p", sess); - sess->enabled = true; - - if (sess->seat && - (!sess->seat->current_sess || - sess->seat->current_sess == sess->seat->dummy_sess)) - seat_schedule(sess->seat, sess); -} - -void uvtd_session_disable(struct uvtd_session *sess) -{ - if (!sess || !sess->enabled) - return; - - log_debug("disable session %p", sess); - sess->enabled = false; -} - -bool uvtd_session_is_enabled(struct uvtd_session *sess) -{ - return sess && sess->enabled; -} - -void uvtd_session_notify_deactivated(struct uvtd_session *sess) -{ - struct uvtd_seat *seat; - unsigned int sched; - - if (!sess || !sess->seat) - return; - - seat = sess->seat; - if (seat->current_sess != sess) - return; - - sched = seat->async_schedule; - log_debug("session %p notified core about deactivation (schedule: %u)", - sess, sched); - seat_yield(seat); - seat_reschedule(seat); - - if (sched == SCHEDULE_SLEEP) - seat_go_asleep(seat, false); - else if (sched == SCHEDULE_UNREGISTER) - uvtd_session_unregister(sess); - else - seat_run(seat); -} diff --git a/src/uvtd_seat.h b/src/uvtd_seat.h deleted file mode 100644 index 534d773..0000000 --- a/src/uvtd_seat.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2012-2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Seats - * Each set of input+output devices form a single seat. Each seat is independent - * of each other and there can be exactly one user per seat interacting with the - * system. - * Per seat, we have multiple sessions. But only one session can be active at a - * time per seat. We allow external sessions, so session activation/deactivation - * may be asynchronous. - */ - -#ifndef UVTD_SEAT_H -#define UVTD_SEAT_H - -#include -#include "eloop.h" - -/* sessions */ - -struct uvtd_session; - -enum uvtd_session_event_type { - UVTD_SESSION_ACTIVATE, - UVTD_SESSION_DEACTIVATE, - UVTD_SESSION_UNREGISTER, -}; - -typedef int (*uvtd_session_cb_t) (struct uvtd_session *session, - unsigned int event, - void *data); - -void uvtd_session_ref(struct uvtd_session *sess); -void uvtd_session_unref(struct uvtd_session *sess); -void uvtd_session_unregister(struct uvtd_session *sess); -bool uvtd_session_is_registered(struct uvtd_session *sess); - -bool uvtd_session_is_active(struct uvtd_session *sess); -void uvtd_session_schedule(struct uvtd_session *sess); - -void uvtd_session_enable(struct uvtd_session *sess); -void uvtd_session_disable(struct uvtd_session *sess); -bool uvtd_session_is_enabled(struct uvtd_session *sess); - -void uvtd_session_notify_deactivated(struct uvtd_session *sess); - -/* seats */ - -struct uvtd_seat; - -enum uvtd_seat_event { - UVTD_SEAT_SLEEP, -}; - -typedef void (*uvtd_seat_cb_t) (struct uvtd_seat *seat, unsigned int event, - void *data); - -int uvtd_seat_new(struct uvtd_seat **out, const char *seatname, - struct ev_eloop *eloop, uvtd_seat_cb_t cb, void *data); -void uvtd_seat_free(struct uvtd_seat *seat); - -const char *uvtd_seat_get_name(struct uvtd_seat *seat); -struct ev_eloop *uvtd_seat_get_eloop(struct uvtd_seat *seat); -int uvtd_seat_sleep(struct uvtd_seat *seat, bool force); -void uvtd_seat_wake_up(struct uvtd_seat *seat); -void uvtd_seat_schedule(struct uvtd_seat *seat, unsigned int id); - -int uvtd_seat_register_session(struct uvtd_seat *seat, - struct uvtd_session **out, - unsigned int id, uvtd_session_cb_t cb, - void *data); - -#endif /* UVTD_SEAT_H */ diff --git a/src/uvtd_vt.c b/src/uvtd_vt.c deleted file mode 100644 index 50eac8e..0000000 --- a/src/uvtd_vt.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2012-2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Virtual Terminals - * Every virtual terminal forms a session inside of uvtd. Sessions are scheduled - * by the seat/session-scheduler and notified whenever they get active/inactive. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "shl_hook.h" -#include "shl_log.h" -#include "uvt.h" -#include "uvtd_seat.h" -#include "uvtd_vt.h" - -#define LOG_SUBSYSTEM "vt" - -struct uvtd_vt { - unsigned long ref; - struct uvt_ctx *uctx; - struct shl_hook *hook; - struct uvtd_session *session; - struct uvtd_seat *seat; - bool is_legacy; - - unsigned int mode; - unsigned int kbmode; - struct vt_mode vtmode; - pid_t vtpid; -}; - -static void vt_hup(struct uvtd_vt *vt) -{ - struct uvt_vt_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.type = UVT_VT_HUP; - - shl_hook_call(vt->hook, vt, &ev); -} - -static int vt_session_event(struct uvtd_session *session, unsigned int event, - void *data) -{ - struct uvtd_vt *vt = data; - - switch (event) { - case UVTD_SESSION_UNREGISTER: - vt->session = NULL; - vt->seat = NULL; - vt_hup(vt); - break; - case UVTD_SESSION_ACTIVATE: - log_debug("activate %p", vt); - break; - case UVTD_SESSION_DEACTIVATE: - log_debug("deactivate %p", vt); - break; - } - - return 0; -} - -int uvtd_vt_new(struct uvtd_vt **out, struct uvt_ctx *uctx, unsigned int id, - struct uvtd_seat *seat, bool is_legacy) -{ - struct uvtd_vt *vt; - int ret; - - if (!out || !uctx) - return -EINVAL; - - vt = malloc(sizeof(*vt)); - if (!vt) - return -ENOMEM; - - memset(vt, 0, sizeof(*vt)); - vt->ref = 1; - vt->uctx = uctx; - vt->seat = seat; - vt->is_legacy = is_legacy; - vt->mode = KD_TEXT; - vt->kbmode = K_UNICODE; - vt->vtmode.mode = VT_AUTO; - - ret = shl_hook_new(&vt->hook); - if (ret) - goto err_free; - - ret = uvtd_seat_register_session(seat, &vt->session, id, - vt_session_event, vt); - if (ret) - goto err_hook; - - uvt_ctx_ref(vt->uctx); - *out = vt; - return 0; - -err_hook: - shl_hook_free(vt->hook); -err_free: - free(vt); - return ret; -} - -void uvtd_vt_ref(struct uvtd_vt *vt) -{ - if (!vt || !vt->ref) - return; - - ++vt->ref; -} - -void uvtd_vt_unref(struct uvtd_vt *vt) -{ - if (!vt || !vt->ref || --vt->ref) - return; - - uvtd_session_unregister(vt->session); - shl_hook_free(vt->hook); - uvt_ctx_unref(vt->uctx); - free(vt); -} - -int uvtd_vt_register_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data) -{ - if (!vt) - return -EINVAL; - - return shl_hook_add_cast(vt->hook, cb, data, false); -} - -void uvtd_vt_unregister_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data) -{ - if (!vt) - return; - - shl_hook_rm_cast(vt->hook, cb, data); -} - -int uvtd_vt_read(struct uvtd_vt *vt, uint8_t *mem, size_t len) -{ - if (!vt || !vt->seat) - return -ENODEV; - - return -EAGAIN; -} - -int uvtd_vt_write(struct uvtd_vt *vt, const uint8_t *mem, size_t len) -{ - if (!vt || !vt->seat) - return -ENODEV; - - return len; -} - -unsigned int uvtd_vt_poll(struct uvtd_vt *vt) -{ - if (!vt || !vt->seat) - return UVT_TTY_HUP | UVT_TTY_READ | UVT_TTY_WRITE; - - return UVT_TTY_WRITE; -} - -static int vt_ioctl_TCFLSH(void *data, unsigned long arg) -{ - switch (arg) { - case TCIFLUSH: - case TCOFLUSH: - case TCIOFLUSH: - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vt_ioctl_VT_ACTIVATE(void *data, unsigned long arg) -{ - struct uvtd_vt *vt = data; - - if (!vt->seat) - return -ENODEV; - - return -EINVAL; -} - -static int vt_ioctl_VT_WAITACTIVE(void *data, unsigned long arg) -{ - struct uvtd_vt *vt = data; - - if (!vt->seat) - return -ENODEV; - - return -EINVAL; -} - -static int vt_ioctl_VT_GETSTATE(void *data, struct vt_stat *arg) -{ - struct uvtd_vt *vt = data; - - if (!vt->seat) - return -ENODEV; - - return -EINVAL; -} - -static int vt_ioctl_VT_OPENQRY(void *data, unsigned int *arg) -{ - struct uvtd_vt *vt = data; - - if (!vt->seat) - return -ENODEV; - - return -EINVAL; -} - -static int vt_ioctl_VT_GETMODE(void *data, struct vt_mode *arg) -{ - struct uvtd_vt *vt = data; - - memcpy(arg, &vt->vtmode, sizeof(*arg)); - return 0; -} - -static int vt_ioctl_VT_SETMODE(void *data, const struct vt_mode *arg, - pid_t pid) -{ - struct uvtd_vt *vt = data; - - /* TODO: implement waitv logic (hang on write if not active) */ - if (arg->waitv) - return -EOPNOTSUPP; - - if (arg->frsig) - return -EINVAL; - if (arg->relsig > SIGRTMAX || arg->relsig < 0) - return -EINVAL; - if (arg->acqsig > SIGRTMAX || arg->acqsig < 0) - return -EINVAL; - - switch (arg->mode) { - case VT_AUTO: - if (arg->acqsig || arg->relsig) - return -EINVAL; - vt->vtpid = 0; - break; - case VT_PROCESS: - vt->vtpid = pid; - break; - default: - return -EINVAL; - } - - memcpy(&vt->vtmode, arg, sizeof(*arg)); - return 0; -} - -static int vt_ioctl_VT_RELDISP(void *data, unsigned long arg) -{ - struct uvtd_vt *vt = data; - - if (!vt->seat) - return -ENODEV; - - return -EINVAL; -} - -static int vt_ioctl_KDGETMODE(void *data, unsigned int *arg) -{ - struct uvtd_vt *vt = data; - - *arg = vt->mode; - return 0; -} - -static int vt_ioctl_KDSETMODE(void *data, unsigned int arg) -{ - struct uvtd_vt *vt = data; - - switch (arg) { - case KD_TEXT0: - case KD_TEXT1: - arg = KD_TEXT; - /* fallthrough */ - case KD_TEXT: - case KD_GRAPHICS: - vt->mode = arg; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vt_ioctl_KDGKBMODE(void *data, unsigned int *arg) -{ - struct uvtd_vt *vt = data; - - *arg = vt->kbmode; - return 0; -} - -static int vt_ioctl_KDSKBMODE(void *data, unsigned int arg) -{ - struct uvtd_vt *vt = data; - - switch (arg) { - case K_RAW: - /* TODO: what does K_RAW do? */ - case K_UNICODE: - case K_OFF: - vt->kbmode = arg; - break; - case K_XLATE: - case K_MEDIUMRAW: - /* TODO: do we need these? */ - return -EOPNOTSUPP; - default: - return -EINVAL; - } - - return 0; -} - -/* compatibility to UVT-VT ops */ - -static void vt_ref(void *vt) -{ - uvtd_vt_ref(vt); -} - -static void vt_unref(void *vt) -{ - uvtd_vt_unref(vt); -} - -static int vt_register_cb(void *vt, uvt_vt_cb cb, void *data) -{ - return uvtd_vt_register_cb(vt, cb, data); -} - -static void vt_unregister_cb(void *vt, uvt_vt_cb cb, void *data) -{ - uvtd_vt_register_cb(vt, cb, data); -} - -static int vt_read(void *vt, uint8_t *mem, size_t len) -{ - return uvtd_vt_read(vt, mem, len); -} - -static int vt_write(void *vt, const uint8_t *mem, size_t len) -{ - return uvtd_vt_write(vt, mem, len); -} - -static unsigned int vt_poll(void *vt) -{ - return uvtd_vt_poll(vt); -} - -struct uvt_vt_ops uvtd_vt_ops = { - .ref = vt_ref, - .unref = vt_unref, - .register_cb = vt_register_cb, - .unregister_cb = vt_unregister_cb, - .read = vt_read, - .write = vt_write, - .poll = vt_poll, - - .ioctl_TCFLSH = vt_ioctl_TCFLSH, - - .ioctl_VT_ACTIVATE = vt_ioctl_VT_ACTIVATE, - .ioctl_VT_WAITACTIVE = vt_ioctl_VT_WAITACTIVE, - .ioctl_VT_GETSTATE = vt_ioctl_VT_GETSTATE, - .ioctl_VT_OPENQRY = vt_ioctl_VT_OPENQRY, - .ioctl_VT_GETMODE = vt_ioctl_VT_GETMODE, - .ioctl_VT_SETMODE = vt_ioctl_VT_SETMODE, - .ioctl_VT_RELDISP = vt_ioctl_VT_RELDISP, - .ioctl_KDGETMODE = vt_ioctl_KDGETMODE, - .ioctl_KDSETMODE = vt_ioctl_KDSETMODE, - .ioctl_KDGKBMODE = vt_ioctl_KDGKBMODE, - .ioctl_KDSKBMODE = vt_ioctl_KDSKBMODE, -}; diff --git a/src/uvtd_vt.h b/src/uvtd_vt.h deleted file mode 100644 index fe83671..0000000 --- a/src/uvtd_vt.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * uvtd - User-space VT daemon - * - * Copyright (c) 2013 David Herrmann - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Virtual Terminals - * Every virtual terminal forms a session inside of uvtd. Sessions are scheduled - * by the seat/session-scheduler and notified whenever they get active/inactive. - */ - -#ifndef UVTD_VT_H -#define UVTD_VT_H - -#include -#include -#include "uvt.h" - -struct uvtd_vt; -extern struct uvt_vt_ops uvtd_vt_ops; - -int uvtd_vt_new(struct uvtd_vt **out, struct uvt_ctx *uctx, unsigned int id, - struct uvtd_seat *seat, bool is_legacy); -void uvtd_vt_ref(struct uvtd_vt *vt); -void uvtd_vt_unref(struct uvtd_vt *vt); - -int uvtd_vt_register_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data); -void uvtd_vt_unregister_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data); - -int uvtd_vt_read(struct uvtd_vt *vt, uint8_t *mem, size_t len); -int uvtd_vt_write(struct uvtd_vt *vt, const uint8_t *mem, size_t len); -unsigned int uvtd_vt_poll(struct uvtd_vt *vt); - -#endif /* UVTD_VT_H */ -- cgit v1.2.3