Make console keymaps configurable through localectl (#4424)

For users having non-English, and especially non-qwerty layouts, using the host
shell can be very awkward. There was no option to change the keymaps as they
haven't been installed in the OS, and the persistence couldn't have been
achieved because of read-only /etc.

With upstream patch merged in #4224, we have an option to put
/etc/vconsole.conf to a writable location and use the same approach as in the
timezone PR. This is needed because even if we only bind-mounted the file from
the overlay directory, the Systemd services which start early will still refer
to the inode on the read-only FS. Also, gzip is required as current version of
kbd in Buildroot (v2.6.4) always compresses the keymaps using gzip. We can get
rid of this after we bump to kbd v2.9.0 [1] or newer. The overall bloat in
local build of the OS is slightly over 1 MiB, so it is acceptable.

With these changes, the `localectl set-keymap` command can be used to use any
available keymap from the installed `kbd` package (refer to `localectl
list-keymaps` for complete lists) and persist it between reboots.

[1] https://github.com/legionus/kbd/releases/tag/v2.9.0

Fixes #1775
This commit is contained in:
Jan Čermák 2025-12-02 17:20:28 +01:00 committed by GitHub
parent 2386b7833b
commit 0354f47ecf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 45 additions and 14 deletions

View File

@ -27,6 +27,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -148,10 +149,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -27,6 +27,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -150,10 +151,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -126,10 +127,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -121,10 +122,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -121,10 +122,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -119,10 +120,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -121,10 +122,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -121,10 +122,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -121,10 +122,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -30,6 +30,7 @@ BR2_PACKAGE_LINUX_TOOLS_HV_VSS_DAEMON=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -151,10 +152,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -30,6 +30,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_CIFS_UTILS=y
@ -125,10 +126,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -30,6 +30,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@ -126,10 +127,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -32,6 +32,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@ -125,10 +126,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -31,6 +31,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_HASSOS_PATH)/busybox.config"
BR2_PACKAGE_BUSYBOX_INDIVIDUAL_BINARIES=y
BR2_PACKAGE_V4L2LOOPBACK=y
BR2_PACKAGE_GZIP=y
BR2_PACKAGE_PIGZ=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@ -129,10 +130,10 @@ BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_SYSTEMD_JOURNAL_REMOTE=y
BR2_PACKAGE_SYSTEMD_COREDUMP=y
# BR2_PACKAGE_SYSTEMD_HWDB is not set
BR2_PACKAGE_SYSTEMD_LOCALED=y
BR2_PACKAGE_SYSTEMD_LOGIND=y
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
BR2_PACKAGE_SYSTEMD_VCONSOLE_DEFAULT_KEYMAP=""
BR2_PACKAGE_UTIL_LINUX_LOGIN=y
BR2_PACKAGE_UTIL_LINUX_NOLOGIN=y
BR2_PACKAGE_UTIL_LINUX_PARTX=y

View File

@ -1,2 +1,3 @@
[Manager]
ManagerEnvironment=SYSTEMD_ETC_LOCALTIME=/mnt/overlay/etc/localtime
ManagerEnvironment=SYSTEMD_ETC_VCONSOLE_CONF=/mnt/overlay/etc/vconsole.conf

View File

@ -0,0 +1,3 @@
[Service]
Environment=SYSTEMD_ETC_VCONSOLE_CONF=/mnt/overlay/etc/vconsole.conf
ReadWritePaths=/etc /mnt/overlay/etc

View File

@ -0,0 +1,2 @@
[Service]
Environment=SYSTEMD_ETC_VCONSOLE_CONF=/mnt/overlay/etc/vconsole.conf

View File

@ -22,3 +22,8 @@ fi
if [ ! -L /mnt/overlay/etc/localtime ]; then
ln -sf /usr/share/zoneinfo/Etc/UTC /mnt/overlay/etc/localtime
fi
# Console
if [ ! -f /mnt/overlay/etc/vconsole.conf ]; then
echo "KEYMAP=us" > /mnt/overlay/etc/vconsole.conf
fi

View File

@ -17,6 +17,7 @@ BOARD_DIR=${2}
fix_rootfs
install_tini_docker
setup_localtime
setup_vconsole
# Write os-release
# shellcheck disable=SC2153

View File

@ -50,3 +50,8 @@ function setup_localtime() {
# localtime is writable through SYSTEMD_ETC_LOCALTIME
ln -fs /mnt/overlay/etc/localtime "${TARGET_DIR}/etc/localtime"
}
function setup_vconsole() {
# vconsole.conf is writable through SYSTEMD_ETC_VCONSOLE_CONF
ln -fs /mnt/overlay/etc/vconsole.conf "${TARGET_DIR}/etc/vconsole.conf"
}