]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
getty-generator: add support for fine-grained control of execution modes
authorAllison Karlitskaya <allison.karlitskaya@redhat.com>
Tue, 24 Jun 2025 08:15:14 +0000 (10:15 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 22 Jul 2025 23:35:51 +0000 (08:35 +0900)
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 <watanabe.yu+github@gmail.com>
man/systemd-getty-generator.xml
man/systemd.system-credentials.xml
src/getty-generator/getty-generator.c

index 574bf9f86b3cbe0c587be8a07b4e8e81482644d9..d02069e630aefc637c46f618ee1a6c6eb1638951 100644 (file)
       <varlistentry>
         <term><varname>systemd.getty_auto=</varname></term>
 
-        <listitem><para>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.
-        </para>
-
-        <xi:include href="version-info.xml" xpointer="v250"/></listitem>
+        <listitem>
+          <para>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: <literal>credential</literal>, <literal>container</literal>, <literal>console</literal>,
+          and <literal>builtin</literal>.</para>
+
+          <para>When <literal>credential</literal> is specified, the two credentials
+          <varname>getty.ttys.serial</varname> and <varname>getty.ttys.container</varname> will be parsed.
+          See System Credentials section below for more details.</para>
+
+          <para>When <literal>container</literal> is specified, <filename>console-getty.service</filename>
+          and <filename>container-getty@.service</filename> will be enabled when the system is running in a
+          container. This option will be ignored when the system is not in a container.</para>
+
+          <para>When <literal>console</literal> is specified, <filename>serial-getty@.service</filename> for
+          active kernel consoles will be enabled. This option will be ignored when the system is running in a
+          container.</para>
+
+          <para>When <literal>builtins</literal> is specified, <filename>serial-getty@.service</filename> for
+          available virtualizer consoles will be enabled. This option will be ignored when the system is
+          running in a container.</para>
+
+          <para>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.
+          </para>
+
+          <xi:include href="version-info.xml" xpointer="v250"/>
+        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
       <varlistentry>
         <term><varname>$SYSTEMD_GETTY_AUTO</varname></term>
 
-        <listitem><para>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.
-        </para>
+        <listitem>
+          <para>This environment variable may be used to control the execution mode of the generator.
+          Takes the same value as <varname>systemd.getty_auto=</varname> kernel command line option.</para>
 
-        <xi:include href="version-info.xml" xpointer="v250"/></listitem>
+          <xi:include href="version-info.xml" xpointer="v250"/>
+        </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
     <title>System Credentials</title>
 
     <variablelist class='system-credentials'>
+      <varlistentry>
+        <term><varname>getty.auto</varname></term>
+
+        <listitem>
+          <para>The system credential may be used to control the execution mode of the generator.
+          Takes the same value as <varname>systemd.getty_auto=</varname> kernel command line option.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>getty.ttys.serial</varname></term>
         <term><varname>getty.ttys.container</varname></term>
         TTYs. The two credentials should contain a newline-separated list of TTY names to spawn instances of
         <filename>serial-getty@.service</filename> (in case of <varname>getty.ttys.serial</varname>) and
         <filename>container-getty@.service</filename> (in case of <varname>getty.ttys.container</varname>)
-        on.</para>
+        on. Any lines starting with a <literal>#</literal> will be ignored.</para>
 
         <xi:include href="version-info.xml" xpointer="v254"/></listitem>
       </varlistentry>
index fd0d12320dae2b74df5b6ff84159dce4d8e590af..1e26654e8d1a75e2b27812abea24c156e421c899 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>getty.auto</varname></term>
+
+        <listitem><para>Used for controlling the execution mode of <filename>systemd-getty-generator</filename>. See
+        <citerefentry><refentrytitle>systemd-getty-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry> for details.</para>
+
+        <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>getty.ttys.serial</varname></term>
         <term><varname>getty.ttys.container</varname></term>
index a4014a8b975d457f9f950d07a527a8879b167462..cd9aae51e3471f1f7ce67ddcb125df10dd5c6c91 100644 (file)
 #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;
 }