From: Allison Karlitskaya Date: Tue, 24 Jun 2025 08:15:14 +0000 (+0200) Subject: getty-generator: add support for fine-grained control of execution modes X-Git-Tag: v258-rc1~10^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a883e89bc1f73c70cb9bd245d5ccc1d805990d7;p=thirdparty%2Fsystemd.git getty-generator: add support for fine-grained control of execution modes This makes the systemd.getty_auto= kernel command line option and the $SYSTEMD_GETTY_AUTO environment variable takes the list of classes of services: credential, container, console, builtin. This also add getty.auto credential that can take the same value as the kernel command line option. Closes #37928. Co-authored-by: Yu Watanabe --- diff --git a/man/systemd-getty-generator.xml b/man/systemd-getty-generator.xml index 574bf9f86b3..d02069e630a 100644 --- a/man/systemd-getty-generator.xml +++ b/man/systemd-getty-generator.xml @@ -64,11 +64,35 @@ systemd.getty_auto= - this options take an optional boolean argument, and default to yes. - The generator is enabled by default, and a false value may be used to disable it. - - - + + This kernel command line option may be used to control the execution mode of the generator. + Takes an optional boolean argument. Since v258, this also takes comma-separated list of special + values: credential, container, console, + and builtin. + + When credential is specified, the two credentials + getty.ttys.serial and getty.ttys.container will be parsed. + See System Credentials section below for more details. + + When container is specified, console-getty.service + and container-getty@.service will be enabled when the system is running in a + container. This option will be ignored when the system is not in a container. + + When console is specified, serial-getty@.service for + active kernel consoles will be enabled. This option will be ignored when the system is running in a + container. + + When builtins is specified, serial-getty@.service for + available virtualizer consoles will be enabled. This option will be ignored when the system is + running in a container. + + When yes, the above four options will be enabled. When no, all options are disabled and no + service will be enabled. When the kernel command line option is specified without an argument, + defaults to yes. The generator is enabled by default, and a false value may be used to disable it. + + + + @@ -80,11 +104,12 @@ $SYSTEMD_GETTY_AUTO - This variable takes an optional boolean argument, and default to yes. - The generator is enabled by default, and a false value may be used to disable it. - + + This environment variable may be used to control the execution mode of the generator. + Takes the same value as systemd.getty_auto= kernel command line option. - + + @@ -93,6 +118,17 @@ System Credentials + + getty.auto + + + The system credential may be used to control the execution mode of the generator. + Takes the same value as systemd.getty_auto= kernel command line option. + + + + + getty.ttys.serial getty.ttys.container @@ -101,7 +137,7 @@ TTYs. The two credentials should contain a newline-separated list of TTY names to spawn instances of serial-getty@.service (in case of getty.ttys.serial) and container-getty@.service (in case of getty.ttys.container) - on. + on. Any lines starting with a # will be ignored. diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index fd0d12320da..1e26654e8d1 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -287,6 +287,15 @@ + + getty.auto + + Used for controlling the execution mode of systemd-getty-generator. See + systemd-getty-generator8 for details. + + + + getty.ttys.serial getty.ttys.container diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c index a4014a8b975..cd9aae51e34 100644 --- a/src/getty-generator/getty-generator.c +++ b/src/getty-generator/getty-generator.c @@ -21,8 +21,17 @@ #include "unit-name.h" #include "virt.h" +typedef enum { + GETTY_SOURCE_NONE = 0, + GETTY_SOURCE_CREDENTIAL = 1 << 0, + GETTY_SOURCE_CONTAINER = 1 << 1, + GETTY_SOURCE_CONSOLE = 1 << 2, + GETTY_SOURCE_BUILTIN = 1 << 3, + GETTY_SOURCE_ALL = GETTY_SOURCE_CREDENTIAL | GETTY_SOURCE_CONTAINER | GETTY_SOURCE_CONSOLE | GETTY_SOURCE_BUILTIN, +} GettySourceFlag; + static const char *arg_dest = NULL; -static bool arg_enabled = true; +static GettySourceFlag arg_getty_sources = GETTY_SOURCE_ALL; static int add_getty_impl(const char *tty, const char *path, const char *type, const char *unit_path) { int r; @@ -166,24 +175,101 @@ static int add_credential_gettys(void) { return 0; } +static int parse_getty_sources(const char *s, GettySourceFlag *ret) { + int r; + + assert(ret); + + if (isempty(s)) { + *ret = GETTY_SOURCE_ALL; + return 0; + } + + r = parse_boolean(s); + if (r >= 0) { + *ret = r ? GETTY_SOURCE_ALL : GETTY_SOURCE_NONE; + return 0; + } + + static struct { + GettySourceFlag flag; + const char *str; + } table[] = { + { GETTY_SOURCE_CREDENTIAL, "credential", }, + { GETTY_SOURCE_CONTAINER, "container", }, + { GETTY_SOURCE_CONSOLE, "console", }, + { GETTY_SOURCE_BUILTIN, "builtin", }, + }; + + GettySourceFlag flags = 0; + for (const char *p = s;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, ",", /* flags = */ 0); + if (r < 0) + return r; + if (r == 0) + break; + + bool found = false; + FOREACH_ELEMENT(i, table) + if (streq(word, i->str)) { + flags |= i->flag; + found = true; + break; + } + + if (!found) + return -EINVAL; + } + + *ret = flags; + return 0; +} + static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; assert(key); if (proc_cmdline_key_streq(key, "systemd.getty_auto")) { - r = value ? parse_boolean(value) : 1; + r = parse_getty_sources(value, &arg_getty_sources); if (r < 0) - log_warning_errno(r, "Failed to parse getty_auto switch \"%s\", ignoring: %m", value); - else - arg_enabled = r; + log_warning_errno(r, "Failed to parse systemd.getty_auto= kernel command line option, ignoring: %s", value); } return 0; } +static void parse_env(void) { + _cleanup_free_ char *value = NULL; + int r; + + r = getenv_for_pid(1, "SYSTEMD_GETTY_AUTO", &value); + if (r < 0) + log_warning_errno(r, "Failed to parse $SYSTEMD_GETTY_AUTO environment variable, ignoring: %m"); + else if (r > 0) { + r = parse_getty_sources(value, &arg_getty_sources); + if (r < 0) + log_warning_errno(r, "Failed to parse $SYSTEMD_GETTY_AUTO environment variable, ignoring: %s", value); + } +} + +static void parse_credentials(void) { + _cleanup_free_ char *value = NULL; + int r; + + r = read_credential_with_decryption("getty.auto", (void**) &value, /* ret_size = */ NULL); + if (r < 0) + log_debug_errno(r, "Failed to read credential 'getty.auto', ignoring: %m"); + else if (r > 0) { + r = parse_getty_sources(value, &arg_getty_sources); + if (r < 0) + log_warning_errno(r, "Invalid 'getty.auto' credential, ignoring: %s", value); + } +} + static int run(const char *dest, const char *dest_early, const char *dest_late) { - _cleanup_free_ char *getty_auto = NULL; int r; assert_se(arg_dest = dest); @@ -197,72 +283,73 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); - r = getenv_for_pid(1, "SYSTEMD_GETTY_AUTO", &getty_auto); - if (r < 0) - log_warning_errno(r, "Failed to parse $SYSTEMD_GETTY_AUTO environment variable, ignoring: %m"); - else if (r > 0) { - r = parse_boolean(getty_auto); - if (r < 0) - log_warning_errno(r, "Failed to parse $SYSTEMD_GETTY_AUTO value \"%s\", ignoring: %m", getty_auto); - else - arg_enabled = r; - } + parse_env(); + parse_credentials(); - if (!arg_enabled) { + if (arg_getty_sources == GETTY_SOURCE_NONE) { log_debug("Disabled, exiting."); return 0; } - r = add_credential_gettys(); - if (r < 0) - return r; + if (FLAGS_SET(arg_getty_sources, GETTY_SOURCE_CREDENTIAL)) { + r = add_credential_gettys(); + if (r < 0) + return r; + } - if (detect_container() > 0) + if (detect_container() > 0) { /* Add console shell and look at $container_ttys, but don't do add any * further magic if we are in a container. */ - return run_container(); + if (FLAGS_SET(arg_getty_sources, GETTY_SOURCE_CONTAINER)) + return run_container(); + + return 0; + } /* Automatically add in a serial getty on all active kernel consoles */ - _cleanup_strv_free_ char **consoles = NULL; - r = get_kernel_consoles(&consoles); - if (r < 0) - log_warning_errno(r, "Failed to get active kernel consoles, ignoring: %m"); - else if (r > 0) - STRV_FOREACH(i, consoles) { - /* We assume that gettys on virtual terminals are started via manual configuration - * and do this magic only for non-VC terminals. */ - if (tty_is_vc(*i)) - continue; + if (FLAGS_SET(arg_getty_sources, GETTY_SOURCE_CONSOLE)) { + _cleanup_strv_free_ char **consoles = NULL; + r = get_kernel_consoles(&consoles); + if (r < 0) + log_warning_errno(r, "Failed to get active kernel consoles, ignoring: %m"); + else if (r > 0) + STRV_FOREACH(i, consoles) { + /* We assume that gettys on virtual terminals are started via manual configuration + * and do this magic only for non-VC terminals. */ + if (tty_is_vc(*i)) + continue; + + if (verify_tty(*i) < 0) + continue; + + r = add_serial_getty(*i); + if (r < 0) + return r; + } + } - if (verify_tty(*i) < 0) + /* Automatically add a serial getty to each available virtualizer console. */ + if (FLAGS_SET(arg_getty_sources, GETTY_SOURCE_BUILTIN)) + FOREACH_STRING(j, + "hvc0", + "xvc0", + "hvsi0", + "sclp_line0", + "ttysclp0", + "3270/tty1") { + _cleanup_free_ char *p = NULL; + + p = path_join("/dev", j); + if (!p) + return log_oom(); + if (access(p, F_OK) < 0) continue; - r = add_serial_getty(*i); + r = add_serial_getty(j); if (r < 0) return r; } - /* Automatically add a serial getty to each available virtualizer console. */ - FOREACH_STRING(j, - "hvc0", - "xvc0", - "hvsi0", - "sclp_line0", - "ttysclp0", - "3270/tty1") { - _cleanup_free_ char *p = NULL; - - p = path_join("/dev", j); - if (!p) - return log_oom(); - if (access(p, F_OK) < 0) - continue; - - r = add_serial_getty(j); - if (r < 0) - return r; - } - return 0; }