]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
firstboot: optionally, don't query for keymap unless connected to a real VT
authorLennart Poettering <lennart@poettering.net>
Fri, 19 Sep 2025 13:42:32 +0000 (15:42 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 26 Sep 2025 14:40:14 +0000 (16:40 +0200)
The keymap only really matters if there's local access to a system, i.e.
if there's actually a physical kbd directly connected to it, to apply it
to. If during firstboot we are not talked to via a VT (but via SSH,
container, or hypervisor console or so instead), then it's very unlikely
we ever are. Hence, don't ask for a keymap, and let#s shortcut the
questions asked at boot.

man/systemd-firstboot.xml
src/firstboot/firstboot.c
test/units/TEST-74-AUX-UTILS.firstboot.sh
units/systemd-firstboot.service

index cc4ddc0cf67adb8487cbbdd23f88d35e77e3c010..26ce7571743a24f382910344cab46b9120f377cc 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--prompt-keymap-auto</option></term>
+
+        <listitem><para>If invoked from a virtual terminal TTY equivalent to
+        <option>--prompt-keymap</option>, otherwise has no effect. Or in other words, only prompts
+        interactively for a keymap if a local keyboard is used for interactivity that requires it.</para>
+
+        <xi:include href="version-info.xml" xpointer="v259"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--copy-locale</option></term>
         <term><option>--copy-keymap</option></term>
index 9637d9f8f6b355475d768f02f1332abfe44fdece..9f237dc266b3ef944aef9ee808818841a61826b7 100644 (file)
@@ -71,6 +71,7 @@ static char *arg_root_shell = NULL;
 static char *arg_kernel_cmdline = NULL;
 static bool arg_prompt_locale = false;
 static bool arg_prompt_keymap = false;
+static bool arg_prompt_keymap_auto = false;
 static bool arg_prompt_timezone = false;
 static bool arg_prompt_hostname = false;
 static bool arg_prompt_root_password = false;
@@ -415,7 +416,21 @@ static int prompt_keymap(int rfd, sd_varlink **mute_console_link) {
                 return 0;
         }
 
-        if (!arg_prompt_keymap) {
+        bool b;
+        if (arg_prompt_keymap_auto) {
+                _cleanup_free_ char *ttyname = NULL;
+
+                r = getttyname_harder(STDOUT_FILENO, &ttyname);
+                if (r < 0) {
+                        log_debug_errno(r, "Cannot determine TTY we are connected, ignoring: %m");
+                        b = false; /* if we can't resolve this, it's probably not a VT */
+                } else {
+                        b = tty_is_vc_resolve(ttyname);
+                        log_debug("Detected connection to local console: %s", yes_no(b));
+                }
+        } else
+                b = arg_prompt_keymap;
+        if (!b) {
                 log_debug("Prompting for keymap was not requested.");
                 return 0;
         }
@@ -1234,6 +1249,8 @@ static int help(void) {
                "                                  Set kernel command line\n"
                "     --prompt-locale              Prompt the user for locale settings\n"
                "     --prompt-keymap              Prompt the user for keymap settings\n"
+               "     --prompt-keymap-auto         Prompt the user for keymap settings if invoked\n"
+               "                                  on local console\n"
                "     --prompt-timezone            Prompt the user for timezone\n"
                "     --prompt-hostname            Prompt the user for hostname\n"
                "     --prompt-root-password       Prompt the user for root password\n"
@@ -1284,6 +1301,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_PROMPT,
                 ARG_PROMPT_LOCALE,
                 ARG_PROMPT_KEYMAP,
+                ARG_PROMPT_KEYMAP_AUTO,
                 ARG_PROMPT_TIMEZONE,
                 ARG_PROMPT_HOSTNAME,
                 ARG_PROMPT_ROOT_PASSWORD,
@@ -1323,6 +1341,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "prompt",                  no_argument,       NULL, ARG_PROMPT                  },
                 { "prompt-locale",           no_argument,       NULL, ARG_PROMPT_LOCALE           },
                 { "prompt-keymap",           no_argument,       NULL, ARG_PROMPT_KEYMAP           },
+                { "prompt-keymap-auto",      no_argument,       NULL, ARG_PROMPT_KEYMAP_AUTO      },
                 { "prompt-timezone",         no_argument,       NULL, ARG_PROMPT_TIMEZONE         },
                 { "prompt-hostname",         no_argument,       NULL, ARG_PROMPT_HOSTNAME         },
                 { "prompt-root-password",    no_argument,       NULL, ARG_PROMPT_ROOT_PASSWORD    },
@@ -1480,6 +1499,7 @@ static int parse_argv(int argc, char *argv[]) {
                 case ARG_PROMPT:
                         arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
                                 arg_prompt_root_password = arg_prompt_root_shell = true;
+                        arg_prompt_keymap_auto = false;
                         break;
 
                 case ARG_PROMPT_LOCALE:
@@ -1488,6 +1508,11 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_PROMPT_KEYMAP:
                         arg_prompt_keymap = true;
+                        arg_prompt_keymap_auto = false;
+                        break;
+
+                case ARG_PROMPT_KEYMAP_AUTO:
+                        arg_prompt_keymap_auto = true;
                         break;
 
                 case ARG_PROMPT_TIMEZONE:
@@ -1668,7 +1693,7 @@ static int run(int argc, char *argv[]) {
                         return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
                 if (r > 0 && !enabled) {
                         log_debug("Found systemd.firstboot=no kernel command line argument, turning off all prompts.");
-                        arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = arg_prompt_root_shell = false;
+                        arg_prompt_locale = arg_prompt_keymap = arg_prompt_keymap_auto = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = arg_prompt_root_shell = false;
                 }
         }
 
index 5f7209231ad106190d638a6c141c3d514e86286e..d6946ba4ee2f4e1bc7e213b582cc4451f58f8ac7 100755 (executable)
@@ -221,6 +221,10 @@ grep -q "LC_MESSAGES=bar" "$ROOT$LOCALE_PATH"
 if [ -d "/usr/share/keymaps/" ] || [ -d "/usr/share/kbd/keymaps/" ] || [ -d "/usr/lib/kbd/keymaps/" ] ; then
    echo -ne "foo\n" | systemd-firstboot --root="$ROOT" --prompt-keymap
    grep -q "KEYMAP=foo" "$ROOT/etc/vconsole.conf"
+
+   rm "$ROOT/etc/vconsole.conf"
+   # this should be a NOP, given that stdout is connected to /dev/null, and hence not a VT
+   systemd-firstboot --root="$ROOT" --prompt-keymap-auto > /dev/null
 fi
 echo -ne "Europe/Berlin\n" | systemd-firstboot --root="$ROOT" --prompt-timezone
 readlink "$ROOT/etc/localtime" | grep -q "Europe/Berlin$"
index 5ba9c8ba03da8af1b63179f7309285cd5af09ba7..fb1c59ad6fbdc2c664d31198208a06e7a77240fc 100644 (file)
@@ -32,7 +32,7 @@ Before=shutdown.target
 [Service]
 Type=oneshot
 RemainAfterExit=yes
-ExecStart=systemd-firstboot --prompt-locale --prompt-keymap --prompt-timezone --prompt-root-password --mute-console=yes
+ExecStart=systemd-firstboot --prompt-locale --prompt-keymap-auto --prompt-timezone --prompt-root-password --mute-console=yes
 StandardOutput=tty
 StandardInput=tty
 StandardError=tty