diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-03-05 01:31:45 +0100 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2013-03-05 01:32:45 +0100 |
commit | c56f5fcb4da83ac45fa5bccaad868c69b368290b (patch) | |
tree | 53cea9ec6a749b99f1c425028c17a6154ebbba7f | |
parent | e28c39c4fb5cfdba220fac525780e5bf15849bdf (diff) |
uvtd: add ctx subsystem
The ctx subsystem manages the CDEV devices for each seat. It currently
allocates one manager device and a given number of legacy devices that can
be accessed via subdirectories.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | src/uvtd_ctx.c | 279 | ||||
-rw-r--r-- | src/uvtd_ctx.h | 46 | ||||
-rw-r--r-- | src/uvtd_main.c | 55 |
4 files changed, 373 insertions, 12 deletions
diff --git a/Makefile.am b/Makefile.am index 0f0c8f6..03e62c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -698,6 +698,8 @@ endif uvtd_SOURCES = \ src/uvtd_main.c \ + src/uvtd_ctx.h \ + src/uvtd_ctx.c \ src/uvtd_seat.h \ src/uvtd_seat.c uvtd_CPPFLAGS = \ @@ -707,7 +709,8 @@ uvtd_LDADD = \ $(XKBCOMMON_LIBS) \ libeloop.la \ libshl.la \ - libuterm.la + libuterm.la \ + libuvt.la # # Tests diff --git a/src/uvtd_ctx.c b/src/uvtd_ctx.c new file mode 100644 index 0000000..1388929 --- /dev/null +++ b/src/uvtd_ctx.c @@ -0,0 +1,279 @@ +/* + * uvtd - User-space VT daemon + * + * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> + * + * 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. + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "eloop.h" +#include "shl_dlist.h" +#include "shl_log.h" +#include "uvt.h" +#include "uvtd_ctx.h" +#include "uvtd_seat.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_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_cdevs; + unsigned int legacy_num; +}; + +static void ctx_legacy_cdev_event(struct uvt_cdev *cdev, + struct uvt_cdev_event *ev, void *data) +{ + switch (ev->type) { + case UVT_CDEV_HUP: + break; + case UVT_CDEV_OPEN: + break; + } +} + +static int ctx_legacy_cdev_init(struct uvtd_ctx *ctx, unsigned int id) +{ + struct ctx_legacy *legacy; + char *name; + int ret; + + legacy = malloc(sizeof(*legacy)); + if (!legacy) + return -ENOMEM; + + 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 = asprintf(&name, "ttysF%s!tty%u", ctx->seatname, legacy->minor); + if (ret <= 0) { + ret = -ENOMEM; + goto err_minor; + } + + ret = uvt_cdev_new(&legacy->cdev, ctx->uctx, name, + uvt_ctx_get_major(ctx->uctx), legacy->minor); + free(name); + + if (ret) + goto err_minor; + + ret = uvt_cdev_register_cb(legacy->cdev, ctx_legacy_cdev_event, + legacy); + if (ret) + goto err_cdev; + + shl_dlist_link(&ctx->legacy_cdevs, &legacy->list); + return 0; + +err_cdev: + 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_cdev_destroy(struct ctx_legacy *legacy) +{ + shl_dlist_unlink(&legacy->list); + 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_cdev_conf(struct uvtd_ctx *ctx, unsigned int num) +{ + struct ctx_legacy *l; + unsigned int i; + int ret; + + if (num > ctx->legacy_num) { + for (i = ctx->legacy_num; i < num; ++i) { + ret = ctx_legacy_cdev_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_cdevs, + struct ctx_legacy, list); + ctx_legacy_cdev_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; + + switch (ev->type) { + case UVT_CDEV_HUP: + log_error("HUP on main cdev on seat %s", ctx->seatname); + break; + case UVT_CDEV_OPEN: + log_debug("new client on main cdev on seat %s", + ctx->seatname); + break; + } +} + +static void ctx_seat_event(struct uvtd_seat *seat, unsigned int ev, void *data) +{ +} + +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; + char *name; + + 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_cdevs); + + ctx->seatname = strdup(seatname); + if (!ctx->seatname) { + ret = -ENOMEM; + goto err_free; + } + + ret = uvtd_seat_new(&ctx->seat, seatname, ctx->eloop, ctx_seat_event, + ctx); + if (ret) + goto err_name; + + ret = uvt_ctx_new_minor(ctx->uctx, &ctx->main_cdev_minor); + if (ret) + goto err_seat; + + ret = asprintf(&name, "ttyF%s", seatname); + if (ret <= 0) { + ret = -ENOMEM; + goto err_minor; + } + + ret = uvt_cdev_new(&ctx->main_cdev, ctx->uctx, name, + uvt_ctx_get_major(ctx->uctx), ctx->main_cdev_minor); + free(name); + + if (ret) + goto err_minor; + + ret = uvt_cdev_register_cb(ctx->main_cdev, ctx_main_cdev_event, ctx); + if (ret) + goto err_cdev; + + ctx_legacy_cdev_conf(ctx, 8); + + ev_eloop_ref(ctx->eloop); + uvt_ctx_ref(ctx->uctx); + *out = ctx; + return 0; + +err_cdev: + uvt_cdev_unref(ctx->main_cdev); +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; + + ctx_legacy_cdev_conf(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); + uvt_ctx_unref(ctx->uctx); + ev_eloop_unref(ctx->eloop); + free(ctx->seatname); + free(ctx); +} diff --git a/src/uvtd_ctx.h b/src/uvtd_ctx.h new file mode 100644 index 0000000..7a17891 --- /dev/null +++ b/src/uvtd_ctx.h @@ -0,0 +1,46 @@ +/* + * uvtd - User-space VT daemon + * + * Copyright (c) 2013 David Herrmann <dh.herrmann@gmail.com> + * + * 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 <stdlib.h> +#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); + +#endif /* UVTD_CTX_H */ diff --git a/src/uvtd_main.c b/src/uvtd_main.c index 0dc7a83..d4b70ff 100644 --- a/src/uvtd_main.c +++ b/src/uvtd_main.c @@ -35,25 +35,24 @@ #include "shl_log.h" #include "uterm_input.h" #include "uterm_monitor.h" -#include "uvtd_seat.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_seat *seat; + 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 void app_seat_event(struct uvtd_seat *seat, unsigned int ev, void *data) -{ -} - static int app_seat_new(struct uvtd_app *app, const char *sname, struct uterm_monitor_seat *useat) { @@ -70,10 +69,13 @@ static int app_seat_new(struct uvtd_app *app, const char *sname, seat->app = app; seat->useat = useat; - ret = uvtd_seat_new(&seat->seat, sname, app->eloop, app_seat_event, - seat); - if (ret) + 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); @@ -90,7 +92,7 @@ static void app_seat_free(struct app_seat *seat) shl_dlist_unlink(&seat->list); uterm_monitor_set_seat_data(seat->useat, NULL); - uvtd_seat_free(seat->seat); + uvtd_ctx_free(seat->ctx); free(seat); } @@ -155,8 +157,23 @@ static void app_sig_ignore(struct ev_eloop *eloop, { } +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); @@ -169,7 +186,7 @@ static void destroy_app(struct uvtd_app *app) static int setup_app(struct uvtd_app *app) { - int ret; + int ret, fd; shl_dlist_init(&app->seats); @@ -206,6 +223,22 @@ static int setup_app(struct uvtd_app *app) 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); |