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 <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-12-06 13:55:00 +01:00
parent b972ebb102
commit 2ac9421377
4 changed files with 97 additions and 39 deletions

View File

@ -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 </foo/bar> [/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 <vt-number> [auto] Select which VT to run on\n"
"\t-s, --switchvt [on] Automatically switch to VT\n"
"\t --vt <vt> [auto] Select which VT to run on\n"
"\t --switchvt [on] Automatically switch to VT\n"
"\t --seats <list,of,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 <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)

View File

@ -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 */

View File

@ -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

View File

@ -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");