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:
parent
b972ebb102
commit
2ac9421377
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user