uvtd: add ctx subsystem
authorDavid Herrmann <dh.herrmann@gmail.com>
Tue, 5 Mar 2013 00:31:45 +0000 (01:31 +0100)
committerDavid Herrmann <dh.herrmann@gmail.com>
Tue, 5 Mar 2013 00:32:45 +0000 (01:32 +0100)
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>
Makefile.am
src/uvtd_ctx.c [new file with mode: 0644]
src/uvtd_ctx.h [new file with mode: 0644]
src/uvtd_main.c

index 0f0c8f6..03e62c8 100644 (file)
@@ -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 (file)
index 0000000..1388929
--- /dev/null
@@ -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 (file)
index 0000000..7a17891
--- /dev/null
@@ -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 */
index 0dc7a83..d4b70ff 100644 (file)
 #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);