From 2ac94213771155431a73cbbafc570b213efaf414 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 6 Dec 2012 13:55:00 +0100 Subject: [PATCH] kmscon: introduce new --listen mode Instead of configuring everything for every kind of situation, we now split kmscon into two modes: default-mode and listen-mode In default-mode we run on the given seats once until we encounter a HUP or until we are closed. It's a perfect replacement for agetty. In listen-mode, we run only on non-VT seats and provide the full kmscon functionality. We run as system daemon and wait for new seats and close seats if they are destroyed. We simply provide a full system-console on all seats. Signed-off-by: David Herrmann --- src/kmscon_conf.c | 41 ++++++++++++++++++++++++++++------------- src/kmscon_conf.h | 26 ++++++++++++++++++++++---- src/kmscon_main.c | 37 ++++++++++++++++++++++++++++++------- src/kmscon_seat.c | 32 +++++++++++++++++--------------- 4 files changed, 97 insertions(+), 39 deletions(-) diff --git a/src/kmscon_conf.c b/src/kmscon_conf.c index f2a4bfb..b23376e 100644 --- a/src/kmscon_conf.c +++ b/src/kmscon_conf.c @@ -55,7 +55,7 @@ static void print_help() "Usage:\n" "\t%1$s [options]\n" "\t%1$s -h [options]\n" - "\t%1$s -l [options] -- /bin/sh [sh-arguments]\n" + "\t%1$s -l [options] -- /bin/login [login-arguments]\n" "\n" "You can prefix boolean options with \"no-\" to negate them. If an argument is\n" "given multiple times, only the last argument matters if not otherwise stated.\n" @@ -67,17 +67,20 @@ static void print_help() "\t --silent [off] Suppress notices and warnings\n" "\t-c, --configdir [/etc/kmscon]\n" "\t Path to config directory\n" + "\t --listen [off] Listen for new seats and spawn\n" + "\t sessions accordingly (daemon mode)\n" "\n" "Seat Options:\n" - "\t --vt [auto] Select which VT to run on\n" - "\t-s, --switchvt [on] Automatically switch to VT\n" + "\t --vt [auto] Select which VT to run on\n" + "\t --switchvt [on] Automatically switch to VT\n" "\t --seats [seat0] Select seats or pass 'all' to make\n" "\t kmscon run on all seats\n" - "\t --cdev [off] Emulate kernel VTs\n" "\n" "Session Options:\n" "\t --session-max [50] Maximum number of sessions\n" - "\t --multi-session [off] Run in multi-session mode\n" + "\t --session-control [off] Allow keyboard session-control\n" + "\t --terminal-session [on] Enable terminal session\n" + "\t --cdev-session [off] Enable kernel VT emulation session\n" "\n" "Terminal Options:\n" "\t-l, --login [/bin/sh]\n" @@ -435,6 +438,12 @@ static int aftercheck_drm(struct conf_option *opt, int argc, char **argv, struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, drm); /* disable --drm if DRM runtime support is not available */ + /* TODO: This prevents people from booting without DRM and loading DRM + * drivers during runtime. However, if we remove it, we will be unable + * to automatically fall back to fbdev-mode. + * But with blacklists fbdev-mode is the default so we can run with DRM + * enabled but will still correctly use fbdev devices so we can then + * remove this check. */ if (conf->drm) { if (!uterm_video_available(UTERM_VIDEO_DRM) && !uterm_video_available(UTERM_VIDEO_DUMB)) { @@ -451,12 +460,13 @@ static int aftercheck_vt(struct conf_option *opt, int argc, char **argv, { struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, vt); - if (!conf->vt) + if (!conf->vt || conf->seat_config) return 0; - if (shl_string_list_is(conf->seats, "all") || - shl_string_list_count(conf->seats, true) != 1) - log_warning("you should use --vt only if --seats contains exactly one seat"); + if (!kmscon_conf_is_single_seat(conf)) { + log_error("you cannot use global --vt if --seats contains not exactly one seat"); + return -EFAULT; + } return 0; } @@ -517,16 +527,18 @@ int kmscon_conf_new(struct conf_ctx **out) CONF_OPTION_BOOL_FULL(0, "debug", aftercheck_debug, NULL, NULL, &conf->debug, false), CONF_OPTION_BOOL(0, "silent", &conf->silent, false), CONF_OPTION_STRING('c', "configdir", &conf->configdir, "/etc/kmscon"), + CONF_OPTION_BOOL(0, "listen", &conf->listen, false), /* Seat Options */ CONF_OPTION(0, 0, "vt", &conf_vt, aftercheck_vt, NULL, NULL, &conf->vt, NULL), - CONF_OPTION_BOOL('s', "switchvt", &conf->switchvt, true), + CONF_OPTION_BOOL(0, "switchvt", &conf->switchvt, true), CONF_OPTION_STRING_LIST(0, "seats", &conf->seats, def_seats), - CONF_OPTION_BOOL(0, "cdev", &conf->cdev, false), /* Session Options */ CONF_OPTION_UINT(0, "session-max", &conf->session_max, 50), - CONF_OPTION_BOOL(0, "multi-session", &conf->multi_session, false), + CONF_OPTION_BOOL(0, "session-control", &conf->session_control, false), + CONF_OPTION_BOOL(0, "terminal-session", &conf->terminal_session, true), + CONF_OPTION_BOOL(0, "cdev-session", &conf->cdev_session, false), /* Terminal Options */ CONF_OPTION(0, 'l', "login", &conf_login, aftercheck_login, NULL, file_login, &conf->login, false), @@ -598,6 +610,7 @@ int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv) return -EINVAL; conf = conf_ctx_get_mem(ctx); + conf->seat_config = false; ret = conf_ctx_parse_argv(ctx, argc, argv); if (ret) @@ -632,11 +645,13 @@ int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main, log_debug("parsing seat configuration for seat %s", seat); + conf = conf_ctx_get_mem(ctx); + conf->seat_config = true; + ret = conf_ctx_parse_ctx(ctx, main); if (ret) return ret; - conf = conf_ctx_get_mem(ctx); ret = conf_ctx_parse_file(ctx, "%s/%s.seat.conf", conf->configdir, seat); if (ret) diff --git a/src/kmscon_conf.h b/src/kmscon_conf.h index 7e6055c..55e3558 100644 --- a/src/kmscon_conf.h +++ b/src/kmscon_conf.h @@ -44,6 +44,9 @@ enum kmscon_conf_gpu_selection { }; struct kmscon_conf_t { + /* header information */ + bool seat_config; + /* General Options */ /* show help/usage information */ bool help; @@ -57,6 +60,8 @@ struct kmscon_conf_t { bool silent; /* config directory name */ char *configdir; + /* listen mode */ + bool listen; /* Seat Options */ /* VT number to run on */ @@ -65,14 +70,16 @@ struct kmscon_conf_t { bool switchvt; /* seats */ char **seats; - /* cdev */ - bool cdev; /* Session Options */ /* sessions */ unsigned int session_max; - /* run in multi-session mode */ - bool multi_session; + /* allow keyboard session control */ + bool session_control; + /* run terminal session */ + bool terminal_session; + /* cdev session */ + bool cdev_session; /* Terminal Options */ /* custom login process */ @@ -149,4 +156,15 @@ int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv); int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main, const char *seat); +static inline bool kmscon_conf_is_all_seats(struct kmscon_conf_t *conf) +{ + return conf && shl_string_list_is(conf->seats, "all"); +} + +static inline bool kmscon_conf_is_single_seat(struct kmscon_conf_t *conf) +{ + return conf && !kmscon_conf_is_all_seats(conf) && + shl_string_list_count(conf->seats, true) == 1; +} + #endif /* KMSCON_MAIN_H */ diff --git a/src/kmscon_main.c b/src/kmscon_main.c index c39afe8..6992719 100644 --- a/src/kmscon_main.c +++ b/src/kmscon_main.c @@ -72,6 +72,7 @@ struct kmscon_app { struct uterm_vt_master *vtm; struct uterm_monitor *mon; struct shl_dlist seats; + unsigned int running_seats; }; static int app_seat_event(struct kmscon_seat *s, unsigned int event, @@ -111,12 +112,28 @@ static int app_seat_event(struct kmscon_seat *s, unsigned int event, kmscon_seat_free(seat->seat); seat->seat = NULL; - if (!shl_string_list_is(app->conf->seats, "all") && - shl_string_list_count(app->conf->seats, true) == 1) { - log_debug("seat HUP in single-seat mode; exiting..."); - ev_eloop_exit(app->eloop); + if (!app->conf->listen) { + --app->running_seats; + if (!app->running_seats) { + log_debug("seat HUP on %s in default-mode; exiting...", + seat->name); + ev_eloop_exit(app->eloop); + } else { + log_debug("seat HUP on %s in default-mode; %u more running seats", + seat->name, app->running_seats); + } } else { - log_debug("seat HUP in multi-seat mode; ignoring..."); + /* Seat HUP here means that we are running in + * listen-mode on a modular-VT like kmscon-fake-VTs. But + * this is an invalid setup. In listen-mode we + * exclusively run as seat-VT-master without a + * controlling VT and we effectively prevent other + * setups during startup. Hence, we can safely drop the + * seat here and ignore it. + * You can destroy and recreate the seat to make kmscon + * pick it up again in listen-mode. */ + log_warning("seat HUP on %s in listen-mode; dropping seat...", + seat->name); } break; @@ -134,7 +151,7 @@ static int app_seat_new(struct kmscon_app *app, struct app_seat **out, bool found; found = false; - if (shl_string_list_is(app->conf->seats, "all")) { + if (kmscon_conf_is_all_seats(app->conf)) { found = true; } else { for (i = 0; app->conf->seats[i]; ++i) { @@ -180,6 +197,7 @@ static int app_seat_new(struct kmscon_app *app, struct app_seat **out, seat->conf = conf_ctx_get_mem(seat->conf_ctx); shl_dlist_link(&app->seats, &seat->list); + ++app->running_seats; *out = seat; return 0; @@ -561,7 +579,12 @@ int main(int argc, char **argv) uterm_vt_master_activate_all(app.vtm); } - ev_eloop_run(app.eloop, -1); + if (!app.conf->listen && !app.running_seats) { + log_notice("no running seats; exiting"); + } else { + log_debug("%u running seats after startup", app.running_seats); + ev_eloop_run(app.eloop, -1); + } if (app.conf->switchvt) { /* The VT subsystem needs to acknowledge the VT-leave so if it diff --git a/src/kmscon_seat.c b/src/kmscon_seat.c index 6b4d9ce..43ccd74 100644 --- a/src/kmscon_seat.c +++ b/src/kmscon_seat.c @@ -560,7 +560,7 @@ static void seat_input_event(struct uterm_input *input, if (conf_grab_matches(seat->conf->grab_session_next, ev->mods, ev->num_syms, ev->keysyms)) { ev->handled = true; - if (!seat->conf->multi_session) + if (!seat->conf->session_control) return; seat_next(seat); return; @@ -568,7 +568,7 @@ static void seat_input_event(struct uterm_input *input, if (conf_grab_matches(seat->conf->grab_session_prev, ev->mods, ev->num_syms, ev->keysyms)) { ev->handled = true; - if (!seat->conf->multi_session) + if (!seat->conf->session_control) return; seat_prev(seat); return; @@ -576,7 +576,7 @@ static void seat_input_event(struct uterm_input *input, if (conf_grab_matches(seat->conf->grab_session_dummy, ev->mods, ev->num_syms, ev->keysyms)) { ev->handled = true; - if (!seat->conf->multi_session) + if (!seat->conf->session_control) return; seat->scheduled_sess = seat->dummy_sess; seat_switch(seat); @@ -585,7 +585,7 @@ static void seat_input_event(struct uterm_input *input, if (conf_grab_matches(seat->conf->grab_session_close, ev->mods, ev->num_syms, ev->keysyms)) { ev->handled = true; - if (!seat->conf->multi_session) + if (!seat->conf->session_control) return; s = seat->current_sess; if (!s) @@ -611,7 +611,7 @@ static void seat_input_event(struct uterm_input *input, if (conf_grab_matches(seat->conf->grab_terminal_new, ev->mods, ev->num_syms, ev->keysyms)) { ev->handled = true; - if (!seat->conf->multi_session) + if (!seat->conf->session_control) return; ret = kmscon_terminal_register(&s, seat); if (ret == -EOPNOTSUPP) { @@ -710,23 +710,25 @@ int kmscon_seat_new(struct kmscon_seat **out, kmscon_session_enable(s); } - ret = kmscon_terminal_register(&s, seat); - if (ret == -EOPNOTSUPP) - log_notice("terminal support not compiled in"); - else if (ret) - goto err_sessions; - else - kmscon_session_enable(s); + if (seat->conf->terminal_session) { + ret = kmscon_terminal_register(&s, seat); + if (ret == -EOPNOTSUPP) + log_notice("terminal support not compiled in"); + else if (ret) + goto err_sessions; + else + kmscon_session_enable(s); + } - if (seat->conf->multi_session && seat->conf->cdev) { + if (seat->conf->cdev_session) { ret = kmscon_cdev_register(&s, seat); if (ret == -EOPNOTSUPP) log_notice("cdev sessions not compiled in"); else if (ret) - log_error("cannot register cdev session: %d", ret); + goto err_sessions; } - if (seat->conf->multi_session) { + if (seat->conf->session_control) { ret = kmscon_compositor_register(&s, seat); if (ret == -EOPNOTSUPP) log_notice("compositor support not compiled in"); -- 2.7.4