summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-03-05 01:31:45 +0100
committerDavid Herrmann <dh.herrmann@gmail.com>2013-03-05 01:32:45 +0100
commitc56f5fcb4da83ac45fa5bccaad868c69b368290b (patch)
tree53cea9ec6a749b99f1c425028c17a6154ebbba7f
parente28c39c4fb5cfdba220fac525780e5bf15849bdf (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.am5
-rw-r--r--src/uvtd_ctx.c279
-rw-r--r--src/uvtd_ctx.h46
-rw-r--r--src/uvtd_main.c55
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);