1
0
mirror of https://github.com/systemd/systemd synced 2025-10-06 00:13:24 +02:00

firstboot: optionally, don't query for keymap unless connected to a real VT

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.
This commit is contained in:
Lennart Poettering
2025-09-19 15:42:32 +02:00
parent bedcce1a1f
commit aa27bec194
4 changed files with 43 additions and 3 deletions

View File

@@ -271,6 +271,17 @@
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><option>--copy-locale</option></term> <term><option>--copy-locale</option></term>
<term><option>--copy-keymap</option></term> <term><option>--copy-keymap</option></term>

View File

@@ -71,6 +71,7 @@ static char *arg_root_shell = NULL;
static char *arg_kernel_cmdline = NULL; static char *arg_kernel_cmdline = NULL;
static bool arg_prompt_locale = false; static bool arg_prompt_locale = false;
static bool arg_prompt_keymap = false; static bool arg_prompt_keymap = false;
static bool arg_prompt_keymap_auto = false;
static bool arg_prompt_timezone = false; static bool arg_prompt_timezone = false;
static bool arg_prompt_hostname = false; static bool arg_prompt_hostname = false;
static bool arg_prompt_root_password = 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; 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."); log_debug("Prompting for keymap was not requested.");
return 0; return 0;
} }
@@ -1234,6 +1249,8 @@ static int help(void) {
" Set kernel command line\n" " Set kernel command line\n"
" --prompt-locale Prompt the user for locale settings\n" " --prompt-locale Prompt the user for locale settings\n"
" --prompt-keymap Prompt the user for keymap 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-timezone Prompt the user for timezone\n"
" --prompt-hostname Prompt the user for hostname\n" " --prompt-hostname Prompt the user for hostname\n"
" --prompt-root-password Prompt the user for root password\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,
ARG_PROMPT_LOCALE, ARG_PROMPT_LOCALE,
ARG_PROMPT_KEYMAP, ARG_PROMPT_KEYMAP,
ARG_PROMPT_KEYMAP_AUTO,
ARG_PROMPT_TIMEZONE, ARG_PROMPT_TIMEZONE,
ARG_PROMPT_HOSTNAME, ARG_PROMPT_HOSTNAME,
ARG_PROMPT_ROOT_PASSWORD, ARG_PROMPT_ROOT_PASSWORD,
@@ -1323,6 +1341,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "prompt", no_argument, NULL, ARG_PROMPT }, { "prompt", no_argument, NULL, ARG_PROMPT },
{ "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE }, { "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE },
{ "prompt-keymap", no_argument, NULL, ARG_PROMPT_KEYMAP }, { "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-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE },
{ "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME }, { "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME },
{ "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD }, { "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: case ARG_PROMPT:
arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
arg_prompt_root_password = arg_prompt_root_shell = true; arg_prompt_root_password = arg_prompt_root_shell = true;
arg_prompt_keymap_auto = false;
break; break;
case ARG_PROMPT_LOCALE: case ARG_PROMPT_LOCALE:
@@ -1488,6 +1508,11 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_PROMPT_KEYMAP: case ARG_PROMPT_KEYMAP:
arg_prompt_keymap = true; arg_prompt_keymap = true;
arg_prompt_keymap_auto = false;
break;
case ARG_PROMPT_KEYMAP_AUTO:
arg_prompt_keymap_auto = true;
break; break;
case ARG_PROMPT_TIMEZONE: 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"); return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
if (r > 0 && !enabled) { if (r > 0 && !enabled) {
log_debug("Found systemd.firstboot=no kernel command line argument, turning off all prompts."); 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;
} }
} }

View File

@@ -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 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 echo -ne "foo\n" | systemd-firstboot --root="$ROOT" --prompt-keymap
grep -q "KEYMAP=foo" "$ROOT/etc/vconsole.conf" 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 fi
echo -ne "Europe/Berlin\n" | systemd-firstboot --root="$ROOT" --prompt-timezone echo -ne "Europe/Berlin\n" | systemd-firstboot --root="$ROOT" --prompt-timezone
readlink "$ROOT/etc/localtime" | grep -q "Europe/Berlin$" readlink "$ROOT/etc/localtime" | grep -q "Europe/Berlin$"

View File

@@ -32,7 +32,7 @@ Before=shutdown.target
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes 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 StandardOutput=tty
StandardInput=tty StandardInput=tty
StandardError=tty StandardError=tty