boot,vconsole: Propagate UEFI HII keyboard layout to the OS
UEFI firmware can report the currently-active keyboard layout via EFI_HII_DATABASE_PROTOCOL.GetKeyboardLayout(). The layout descriptor includes an RFC 4646 / BCP 47 language tag (e.g. "en-US"). Query this from sd-boot/sd-stub and write it to a new LoaderKeyboardLayout EFI variable, advertised through a new EFI_LOADER_FEATURE_KEYBOARD_LAYOUT feature bit. On the OS side, systemd-vconsole-setup reads the variable as a lowest-priority fallback for the console keymap. To map the BCP 47 tag to a vconsole keymap we extend /usr/share/systemd/kbd-model-map with an optional sixth column listing the comma-separated BCP 47 tags each row covers; a new find_vconsole_keymap_for_bcp47() helper walks the file, preferring an exact tag match and otherwise falling back to the row whose tag matches the input's primary subtag. Credentials, /etc/vconsole.conf, and vconsole.keymap= on the kernel command line continue to take precedence. bootctl status surfaces the new variable, printing the language tag or "n/a (not reported by firmware)" when sd-boot advertises the feature but the firmware HII database didn't expose a layout (common on QEMU without a USB keyboard, since EDK2's PS/2 driver does not register an HII keyboard layout).
This commit is contained in:
committed by
Daan De Meyer
parent
6f49c7e598
commit
7b9d76cba7
@@ -143,6 +143,8 @@ Variables will be listed below using the Linux efivarfs naming,
|
||||
* `1 << 18` → The boot loader reports active TPM2 PCR banks in the
|
||||
EFI variable `LoaderTpm2ActivePcrBanks-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`.
|
||||
* `1 << 19` → The boot loader supports the `LoaderEntryPreferred` variable when set.
|
||||
* `1 << 20` → The boot loader reports the firmware-configured keyboard layout in the
|
||||
EFI variable `LoaderKeyboardLayout-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`.
|
||||
|
||||
* The EFI variable `LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`
|
||||
contains binary random data,
|
||||
@@ -171,6 +173,17 @@ Variables will be listed below using the Linux efivarfs naming,
|
||||
the TCG EFI ProtocolSpecification for TPM 2.0 as `EFI_TCG2_BOOT_HASH_ALG_*`.
|
||||
If no TPM2 support or no active banks were detected, will be set to `0`.
|
||||
|
||||
* The EFI variable `LoaderKeyboardLayout-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`
|
||||
contains the RFC 4646 (BCP 47) language tag of the currently-active keyboard
|
||||
layout as reported by the UEFI HII database (e.g. `en-US`, `de-DE`).
|
||||
It is formatted as a NUL-terminated UTF-16 string.
|
||||
The boot loader sets this variable from the layout returned by
|
||||
`EFI_HII_DATABASE_PROTOCOL.GetKeyboardLayout()`,
|
||||
if that protocol is implemented by the firmware.
|
||||
Userspace (notably `systemd-vconsole-setup`)
|
||||
uses this as a lowest-priority fallback keyboard layout
|
||||
when no explicit configuration is provided.
|
||||
|
||||
If `LoaderTimeInitUSec` and `LoaderTimeExecUSec` are set, `systemd-analyze`
|
||||
will include them in its boot-time analysis. If `LoaderDevicePartUUID` is set,
|
||||
systemd will mount the ESP that was used for the boot to `/boot`, but only if
|
||||
|
||||
@@ -95,6 +95,20 @@
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Firmware-provided keyboard layout</title>
|
||||
|
||||
<para>If the boot loader reports the firmware-configured keyboard layout via the
|
||||
<varname>LoaderKeyboardLayout</varname> EFI variable (see the
|
||||
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>),
|
||||
<command>systemd-vconsole-setup</command> uses it as the lowest-priority fallback for the
|
||||
keymap. The RFC 4646 / BCP 47 language tag reported by the firmware (e.g. <literal>de-DE</literal>) is
|
||||
matched against the optional sixth column of <filename>/usr/share/systemd/kbd-model-map</filename>,
|
||||
which lists the language tags each virtual-console keymap covers. Credentials,
|
||||
<filename>/etc/vconsole.conf</filename>, and kernel command line options all override this
|
||||
firmware-provided default.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
|
||||
@@ -56,6 +56,13 @@
|
||||
might be checked for configuration of the virtual console as well,
|
||||
however only as fallback.</para>
|
||||
|
||||
<para>If the boot loader reports the firmware-configured keyboard layout via the
|
||||
<varname>LoaderKeyboardLayout</varname> EFI variable (see the
|
||||
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>),
|
||||
it is used as the lowest-priority fallback for <varname>KEYMAP=</varname>.
|
||||
Any setting from credentials, <filename>/etc/vconsole.conf</filename>, or the kernel
|
||||
command line overrides it.</para>
|
||||
|
||||
<para><filename>/etc/vconsole.conf</filename> is usually created and updated
|
||||
using
|
||||
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
|
||||
|
||||
@@ -3266,6 +3266,7 @@ static void export_loader_variables(
|
||||
EFI_LOADER_FEATURE_TYPE1_UKI |
|
||||
EFI_LOADER_FEATURE_TYPE1_UKI_URL |
|
||||
EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS |
|
||||
EFI_LOADER_FEATURE_KEYBOARD_LAYOUT |
|
||||
0;
|
||||
|
||||
assert(loaded_image);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "device-path-util.h"
|
||||
#include "efi-efivars.h"
|
||||
#include "export-vars.h"
|
||||
#include "hii.h"
|
||||
#include "measure.h"
|
||||
#include "part-discovery.h"
|
||||
#include "url-discovery.h"
|
||||
@@ -60,4 +61,13 @@ void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
|
||||
s = xasprintf("0x%08x", active_pcr_banks);
|
||||
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderTpm2ActivePcrBanks", s, 0);
|
||||
}
|
||||
|
||||
/* Report the firmware's currently-active HII keyboard layout (as an RFC 4646 language tag, e.g.
|
||||
* "de-DE"), so the OS can pick a matching console keymap. Best-effort: many firmwares do not
|
||||
* implement the HII database protocol or expose no keyboard layout. */
|
||||
if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderKeyboardLayout", /* ret_data= */ NULL, /* ret_size= */ NULL) != EFI_SUCCESS) {
|
||||
_cleanup_free_ char16_t *lang = hii_query_keyboard_layout_language();
|
||||
if (lang)
|
||||
efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderKeyboardLayout", lang, /* flags= */ 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "efi-log.h"
|
||||
#include "hii.h"
|
||||
#include "proto/hii-database.h"
|
||||
#include "util.h"
|
||||
|
||||
char16_t *hii_query_keyboard_layout_language(void) {
|
||||
EFI_HII_DATABASE_PROTOCOL *hii_db = NULL;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_HII_DATABASE_PROTOCOL), /* Registration= */ NULL, (void **) &hii_db);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_debug_status(err, "HII database protocol not available, ignoring: %m");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* First call sizes the layout. We pass length=0 / buffer=NULL and expect EFI_BUFFER_TOO_SMALL. */
|
||||
uint16_t length = 0;
|
||||
err = hii_db->GetKeyboardLayout(hii_db, /* KeyGuid= */ NULL, &length, /* KeyboardLayout= */ NULL);
|
||||
if (err != EFI_BUFFER_TOO_SMALL) {
|
||||
log_debug_status(err, "Initial GetKeyboardLayout did not report required buffer size, ignoring: %m");
|
||||
return NULL;
|
||||
}
|
||||
if (length < sizeof(EFI_HII_KEYBOARD_LAYOUT)) {
|
||||
log_debug("Reported keyboard layout size %u is smaller than the header, ignoring.", length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_cleanup_free_ EFI_HII_KEYBOARD_LAYOUT *layout = xmalloc(length);
|
||||
err = hii_db->GetKeyboardLayout(hii_db, /* KeyGuid= */ NULL, &length, layout);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_debug_status(err, "Failed to retrieve current keyboard layout, ignoring: %m");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length < sizeof(EFI_HII_KEYBOARD_LAYOUT)) {
|
||||
log_debug("Reported keyboard layout size %u shrank below the header, ignoring.", length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (layout->LayoutLength != length) {
|
||||
log_debug("Keyboard layout reports inconsistent LayoutLength %u vs %u, ignoring.",
|
||||
layout->LayoutLength, length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t off = layout->LayoutDescriptorStringOffset;
|
||||
if (off > length || length - off < sizeof(EFI_DESCRIPTION_STRING_BUNDLE)) {
|
||||
log_debug("Keyboard layout descriptor string offset %u out of bounds (length %u), ignoring.",
|
||||
off, length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EFI_DESCRIPTION_STRING_BUNDLE *bundle = (const EFI_DESCRIPTION_STRING_BUNDLE *) ((const uint8_t *) layout + off);
|
||||
if (bundle->DescriptionCount == 0) {
|
||||
log_debug("Keyboard layout has no description strings, ignoring.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Walk Strings[] looking for the U+0020 that terminates the first language tag. */
|
||||
size_t max_chars = (length - off - sizeof(EFI_DESCRIPTION_STRING_BUNDLE)) / sizeof(char16_t);
|
||||
size_t n;
|
||||
for (n = 0; n < max_chars; n++)
|
||||
if (bundle->Strings[n] == u' ')
|
||||
break;
|
||||
if (n == max_chars) {
|
||||
log_debug("Keyboard layout language tag is not terminated by a space, ignoring.");
|
||||
return NULL;
|
||||
}
|
||||
if (n == 0) {
|
||||
log_debug("Keyboard layout language tag is empty, ignoring.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char16_t *s = xnew(char16_t, n + 1);
|
||||
memcpy(s, bundle->Strings, n * sizeof(char16_t));
|
||||
s[n] = u'\0';
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
/* Queries the firmware's HII database for the currently-active keyboard layout and returns the RFC 4646
|
||||
* language tag (e.g. u"de-DE") embedded in the layout description bundle. Returns NULL if the protocol
|
||||
* is not provided, the table is malformed, or no language tag is present. */
|
||||
char16_t *hii_query_keyboard_layout_language(void);
|
||||
@@ -320,6 +320,7 @@ libefi_sources = files(
|
||||
'efi-string.c',
|
||||
'export-vars.c',
|
||||
'graphics.c',
|
||||
'hii.c',
|
||||
'initrd.c',
|
||||
'measure.c',
|
||||
'part-discovery.c',
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
#define EFI_HII_DATABASE_PROTOCOL_GUID \
|
||||
GUID_DEF(0xef9fc172, 0xa1b2, 0x4693, 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
|
||||
|
||||
typedef void *EFI_HII_HANDLE;
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID PackageListGuid;
|
||||
uint32_t PackageLength;
|
||||
} EFI_HII_PACKAGE_LIST_HEADER;
|
||||
|
||||
typedef struct _packed_ {
|
||||
uint32_t LengthAndType; /* Length:24 | Type:8 (little-endian) */
|
||||
} EFI_HII_PACKAGE_HEADER;
|
||||
|
||||
typedef size_t EFI_HII_DATABASE_NOTIFY_TYPE;
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_HII_DATABASE_NOTIFY)(
|
||||
uint8_t PackageType,
|
||||
EFI_GUID *PackageGuid,
|
||||
EFI_HII_PACKAGE_HEADER *Package,
|
||||
EFI_HII_HANDLE Handle,
|
||||
EFI_HII_DATABASE_NOTIFY_TYPE NotifyType);
|
||||
|
||||
typedef struct EFI_HII_DATABASE_PROTOCOL EFI_HII_DATABASE_PROTOCOL;
|
||||
|
||||
struct EFI_HII_DATABASE_PROTOCOL {
|
||||
EFI_STATUS (EFIAPI *NewPackageList)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_HII_PACKAGE_LIST_HEADER *PackageList,
|
||||
EFI_HANDLE DriverHandle,
|
||||
EFI_HII_HANDLE *Handle);
|
||||
|
||||
EFI_STATUS (EFIAPI *RemovePackageList)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_HII_HANDLE Handle);
|
||||
|
||||
EFI_STATUS (EFIAPI *UpdatePackageList)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_HII_HANDLE Handle,
|
||||
EFI_HII_PACKAGE_LIST_HEADER *PackageList);
|
||||
|
||||
EFI_STATUS (EFIAPI *ListPackageLists)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
uint8_t PackageType,
|
||||
EFI_GUID *PackageGuid,
|
||||
size_t *HandleBufferLength,
|
||||
EFI_HII_HANDLE *Handle);
|
||||
|
||||
EFI_STATUS (EFIAPI *ExportPackageLists)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_HII_HANDLE Handle,
|
||||
size_t *BufferSize,
|
||||
EFI_HII_PACKAGE_LIST_HEADER *Buffer);
|
||||
|
||||
EFI_STATUS (EFIAPI *RegisterPackageNotify)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
uint8_t PackageType,
|
||||
EFI_GUID *PackageGuid,
|
||||
EFI_HII_DATABASE_NOTIFY PackageNotifyFn,
|
||||
EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
|
||||
EFI_HANDLE *NotifyHandle);
|
||||
|
||||
EFI_STATUS (EFIAPI *UnregisterPackageNotify)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_HANDLE NotificationHandle);
|
||||
|
||||
EFI_STATUS (EFIAPI *FindKeyboardLayouts)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
uint16_t *KeyGuidBufferLength,
|
||||
EFI_GUID *KeyGuidBuffer);
|
||||
|
||||
EFI_STATUS (EFIAPI *GetKeyboardLayout)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_GUID *KeyGuid,
|
||||
uint16_t *KeyboardLayoutLength,
|
||||
void *KeyboardLayout);
|
||||
|
||||
EFI_STATUS (EFIAPI *SetKeyboardLayout)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_GUID *KeyGuid);
|
||||
|
||||
EFI_STATUS (EFIAPI *GetPackageListHandle)(
|
||||
EFI_HII_DATABASE_PROTOCOL *This,
|
||||
EFI_HII_HANDLE PackageListHandle,
|
||||
EFI_HANDLE *DriverHandle);
|
||||
};
|
||||
|
||||
/* EFI_HII_KEYBOARD_LAYOUT and EFI_KEY_DESCRIPTOR are packed: LayoutDescriptorStringOffset follows
|
||||
* a 16-byte EFI_GUID at offset 2, so it is at offset 18 — *not* a natural 4-byte alignment. */
|
||||
typedef struct _packed_ {
|
||||
uint16_t LayoutLength;
|
||||
EFI_GUID Guid;
|
||||
uint32_t LayoutDescriptorStringOffset;
|
||||
uint8_t DescriptorCount;
|
||||
/* EFI_KEY_DESCRIPTOR Descriptors[DescriptorCount] follows here, then at
|
||||
* LayoutDescriptorStringOffset (from the start of this struct) the description-string bundle. */
|
||||
} EFI_HII_KEYBOARD_LAYOUT;
|
||||
|
||||
typedef struct _packed_ {
|
||||
uint32_t Key;
|
||||
char16_t Unicode;
|
||||
char16_t ShiftedUnicode;
|
||||
char16_t AltGrUnicode;
|
||||
char16_t ShiftedAltGrUnicode;
|
||||
uint16_t Modifier;
|
||||
uint16_t AffectedAttribute;
|
||||
} EFI_KEY_DESCRIPTOR;
|
||||
|
||||
/* The description-string bundle that LayoutDescriptorStringOffset points to. After DescriptionCount,
|
||||
* each of the DescriptionCount entries is laid out as:
|
||||
*
|
||||
* CHAR16 Language[]; // RFC 4646 tag, terminated by the Space below (no NUL)
|
||||
* CHAR16 Space; // U+0020
|
||||
* CHAR16 DescriptionString[]; // NUL-terminated UTF-16 description
|
||||
*
|
||||
* Despite what the UEFI spec text says, Language is encoded as UTF-16 (CHAR16) in practice — see EDK2
|
||||
* MdeModulePkg/Bus/Usb/UsbKbDxe/KeyBoard.h USB_KEYBOARD_LAYOUT_PACK_BIN. */
|
||||
typedef struct _packed_ {
|
||||
uint16_t DescriptionCount;
|
||||
char16_t Strings[];
|
||||
} EFI_DESCRIPTION_STRING_BUNDLE;
|
||||
@@ -320,7 +320,7 @@ static int efi_get_variable_path_and_warn(const char *variable, char **ret) {
|
||||
|
||||
static void print_yes_no_line(bool first, bool good, const char *name) {
|
||||
printf("%s%s %s\n",
|
||||
first ? " Features: " : " ",
|
||||
first ? " Features: " : " ",
|
||||
COLOR_MARK_BOOL(good),
|
||||
name);
|
||||
}
|
||||
@@ -387,25 +387,26 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
uint64_t flag;
|
||||
const char *name;
|
||||
} loader_flags[] = {
|
||||
{ EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
|
||||
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
|
||||
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
|
||||
{ EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
|
||||
{ EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
|
||||
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
|
||||
{ EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
|
||||
{ EFI_LOADER_FEATURE_LOAD_DRIVER, "Load drop-in drivers" },
|
||||
{ EFI_LOADER_FEATURE_SORT_KEY, "Support Type #1 sort-key field" },
|
||||
{ EFI_LOADER_FEATURE_SAVED_ENTRY, "Support @saved pseudo-entry" },
|
||||
{ EFI_LOADER_FEATURE_DEVICETREE, "Support Type #1 devicetree field" },
|
||||
{ EFI_LOADER_FEATURE_SECUREBOOT_ENROLL, "Enroll SecureBoot keys" },
|
||||
{ EFI_LOADER_FEATURE_RETAIN_SHIM, "Retain SHIM protocols" },
|
||||
{ EFI_LOADER_FEATURE_MENU_DISABLE, "Menu can be disabled" },
|
||||
{ EFI_LOADER_FEATURE_MULTI_PROFILE_UKI, "Multi-Profile UKIs are supported" },
|
||||
{ EFI_LOADER_FEATURE_REPORT_URL, "Loader reports network boot URL" },
|
||||
{ EFI_LOADER_FEATURE_TYPE1_UKI, "Support Type #1 uki field" },
|
||||
{ EFI_LOADER_FEATURE_TYPE1_UKI_URL, "Support Type #1 uki-url field" },
|
||||
{ EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS, "Loader reports active TPM2 PCR banks" },
|
||||
{ EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
|
||||
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
|
||||
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
|
||||
{ EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
|
||||
{ EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
|
||||
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
|
||||
{ EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
|
||||
{ EFI_LOADER_FEATURE_LOAD_DRIVER, "Load drop-in drivers" },
|
||||
{ EFI_LOADER_FEATURE_SORT_KEY, "Support Type #1 sort-key field" },
|
||||
{ EFI_LOADER_FEATURE_SAVED_ENTRY, "Support @saved pseudo-entry" },
|
||||
{ EFI_LOADER_FEATURE_DEVICETREE, "Support Type #1 devicetree field" },
|
||||
{ EFI_LOADER_FEATURE_SECUREBOOT_ENROLL, "Enroll SecureBoot keys" },
|
||||
{ EFI_LOADER_FEATURE_RETAIN_SHIM, "Retain SHIM protocols" },
|
||||
{ EFI_LOADER_FEATURE_MENU_DISABLE, "Menu can be disabled" },
|
||||
{ EFI_LOADER_FEATURE_MULTI_PROFILE_UKI, "Multi-Profile UKIs are supported" },
|
||||
{ EFI_LOADER_FEATURE_REPORT_URL, "Loader reports network boot URL" },
|
||||
{ EFI_LOADER_FEATURE_TYPE1_UKI, "Support Type #1 uki field" },
|
||||
{ EFI_LOADER_FEATURE_TYPE1_UKI_URL, "Support Type #1 uki-url field" },
|
||||
{ EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS, "Loader reports active TPM2 PCR banks" },
|
||||
{ EFI_LOADER_FEATURE_KEYBOARD_LAYOUT, "Loader reports firmware keyboard layout" },
|
||||
};
|
||||
static const struct {
|
||||
uint64_t flag;
|
||||
@@ -426,7 +427,7 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
};
|
||||
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
|
||||
*current_entry = NULL, *oneshot_entry = NULL, *preferred_entry = NULL, *default_entry = NULL, *sysfail_entry = NULL,
|
||||
*sysfail_reason = NULL;
|
||||
*sysfail_reason = NULL, *keyboard_layout = NULL;
|
||||
uint64_t loader_features = 0, stub_features = 0;
|
||||
int have;
|
||||
|
||||
@@ -444,6 +445,7 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), &default_entry);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail"), &sysfail_entry);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderSysFailReason"), &sysfail_reason);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderKeyboardLayout"), &keyboard_layout);
|
||||
|
||||
SecureBootMode secure = efi_get_secure_boot_mode();
|
||||
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
|
||||
@@ -503,7 +505,7 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
|
||||
if (loader) {
|
||||
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
||||
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
||||
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
||||
|
||||
@@ -521,38 +523,42 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
SD_ID128_FORMAT_VAL(loader_partition_uuid),
|
||||
SD_ID128_FORMAT_VAL(esp_uuid));
|
||||
|
||||
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
SD_ID128_FORMAT_VAL(loader_partition_uuid));
|
||||
} else if (loader_path)
|
||||
printf(" Partition: n/a\n");
|
||||
printf(" Partition: n/a\n");
|
||||
|
||||
if (loader_path)
|
||||
printf(" Loader: %s%s%s/%s%s\n",
|
||||
printf(" Loader: %s%s%s/%s%s\n",
|
||||
glyph(GLYPH_TREE_RIGHT), ansi_grey(), arg_esp_path, ansi_normal(), loader_path);
|
||||
|
||||
if (loader_url)
|
||||
printf(" Net Boot URL: %s\n", loader_url);
|
||||
printf(" Net Boot URL: %s\n", loader_url);
|
||||
|
||||
if (FLAGS_SET(loader_features, EFI_LOADER_FEATURE_KEYBOARD_LAYOUT))
|
||||
printf("Keyboard Layout: %s\n",
|
||||
keyboard_layout ?: "n/a (not reported by firmware)");
|
||||
|
||||
if (sysfail_entry)
|
||||
printf("SysFail Reason: %s\n", sysfail_reason);
|
||||
printf(" SysFail Reason: %s\n", sysfail_reason);
|
||||
|
||||
if (current_entry)
|
||||
printf(" Current Entry: %s\n", current_entry);
|
||||
printf(" Current Entry: %s\n", current_entry);
|
||||
if (preferred_entry)
|
||||
printf(" Preferred Entry: %s\n", preferred_entry);
|
||||
printf("Preferred Entry: %s\n", preferred_entry);
|
||||
if (default_entry)
|
||||
printf(" Default Entry: %s\n", default_entry);
|
||||
printf(" Default Entry: %s\n", default_entry);
|
||||
if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
|
||||
printf(" OneShot Entry: %s\n", oneshot_entry);
|
||||
printf(" OneShot Entry: %s\n", oneshot_entry);
|
||||
if (sysfail_entry)
|
||||
printf(" SysFail Entry: %s\n", sysfail_entry);
|
||||
printf(" SysFail Entry: %s\n", sysfail_entry);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (stub) {
|
||||
printf("%sCurrent Stub:%s\n", ansi_underline(), ansi_normal());
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), stub, ansi_normal());
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), stub, ansi_normal());
|
||||
for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
|
||||
print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
|
||||
|
||||
@@ -573,16 +579,16 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
SD_ID128_FORMAT_VAL(esp_uuid),
|
||||
SD_ID128_FORMAT_VAL(xbootldr_uuid));
|
||||
|
||||
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
SD_ID128_FORMAT_VAL(stub_partition_uuid));
|
||||
} else if (stub_path)
|
||||
printf(" Partition: n/a\n");
|
||||
printf(" Partition: n/a\n");
|
||||
|
||||
if (stub_path)
|
||||
printf(" Stub: %s%s\n", glyph(GLYPH_TREE_RIGHT), strna(stub_path));
|
||||
printf(" Stub: %s%s\n", glyph(GLYPH_TREE_RIGHT), strna(stub_path));
|
||||
|
||||
if (stub_url)
|
||||
printf(" Net Boot URL: %s\n", stub_url);
|
||||
printf(" Net Boot URL: %s\n", stub_url);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define EFI_LOADER_FEATURE_TYPE1_UKI_URL (UINT64_C(1) << 17)
|
||||
#define EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS (UINT64_C(1) << 18)
|
||||
#define EFI_LOADER_FEATURE_ENTRY_PREFERRED (UINT64_C(1) << 19)
|
||||
#define EFI_LOADER_FEATURE_KEYBOARD_LAYOUT (UINT64_C(1) << 20)
|
||||
|
||||
/* Features of the stub, i.e. systemd-stub */
|
||||
#define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION (UINT64_C(1) << 0)
|
||||
|
||||
+75
-72
@@ -1,73 +1,76 @@
|
||||
# Originally generated from system-config-keyboard's model list.
|
||||
# consolelayout xlayout xmodel xvariant xoptions
|
||||
sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
|
||||
nl nl pc105 - terminate:ctrl_alt_bksp
|
||||
mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
trq tr pc105 - terminate:ctrl_alt_bksp
|
||||
uk gb pc105 - terminate:ctrl_alt_bksp
|
||||
is-latin1 is pc105 - terminate:ctrl_alt_bksp
|
||||
de de pc105 - terminate:ctrl_alt_bksp
|
||||
la-latin1 latam pc105 - terminate:ctrl_alt_bksp
|
||||
us us pc105+inet - terminate:ctrl_alt_bksp
|
||||
ko kr pc105 - terminate:ctrl_alt_bksp
|
||||
ro-std ro pc105 std terminate:ctrl_alt_bksp
|
||||
de-latin1 de pc105 - terminate:ctrl_alt_bksp
|
||||
slovene si pc105 - terminate:ctrl_alt_bksp
|
||||
hu hu pc105 - terminate:ctrl_alt_bksp
|
||||
jp106 jp jp106 - terminate:ctrl_alt_bksp
|
||||
croat hr pc105 - terminate:ctrl_alt_bksp
|
||||
it2 it pc105 - terminate:ctrl_alt_bksp
|
||||
hu101 hu pc105 qwerty terminate:ctrl_alt_bksp
|
||||
sr-latin rs pc105 latin terminate:ctrl_alt_bksp
|
||||
fi fi pc105 - terminate:ctrl_alt_bksp
|
||||
fr_CH ch pc105 fr terminate:ctrl_alt_bksp
|
||||
dk-latin1 dk pc105 - terminate:ctrl_alt_bksp
|
||||
fr fr pc105 - terminate:ctrl_alt_bksp
|
||||
it it pc105 - terminate:ctrl_alt_bksp
|
||||
ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
fr-latin1 fr pc105 - terminate:ctrl_alt_bksp
|
||||
sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
|
||||
be-latin1 be pc105 - terminate:ctrl_alt_bksp
|
||||
dk dk pc105 - terminate:ctrl_alt_bksp
|
||||
fr-pc fr pc105 - terminate:ctrl_alt_bksp
|
||||
bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
it-ibm it pc105 - terminate:ctrl_alt_bksp
|
||||
cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
cz-qwerty cz,us pc105 qwerty, terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
br-abnt2 br abnt2 - terminate:ctrl_alt_bksp
|
||||
ro ro pc105 - terminate:ctrl_alt_bksp
|
||||
us-acentos us pc105 intl terminate:ctrl_alt_bksp
|
||||
pt-latin1 pt pc105 - terminate:ctrl_alt_bksp
|
||||
ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp
|
||||
tj_alt-UTF8 tj pc105 - terminate:ctrl_alt_bksp
|
||||
de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp
|
||||
no no pc105 - terminate:ctrl_alt_bksp
|
||||
bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
dvorak us pc105 dvorak terminate:ctrl_alt_bksp
|
||||
dvorak us pc105 dvorak-alt-intl terminate:ctrl_alt_bksp
|
||||
ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp
|
||||
pl2 pl pc105 - terminate:ctrl_alt_bksp
|
||||
es es pc105 - terminate:ctrl_alt_bksp
|
||||
ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp
|
||||
ie ie pc105 - terminate:ctrl_alt_bksp
|
||||
et ee pc105 - terminate:ctrl_alt_bksp
|
||||
sk-qwerty sk pc105 qwerty terminate:ctrl_alt_bksp
|
||||
sk-qwertz sk pc105 - terminate:ctrl_alt_bksp
|
||||
fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp
|
||||
fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp
|
||||
cf ca pc105 - terminate:ctrl_alt_bksp
|
||||
sv-latin1 se pc105 - terminate:ctrl_alt_bksp
|
||||
sr-cy rs pc105 - terminate:ctrl_alt_bksp
|
||||
gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
by by,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
il il pc105 - terminate:ctrl_alt_bksp
|
||||
kazakh kz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
|
||||
lt.baltic lt pc105 - terminate:ctrl_alt_bksp
|
||||
lt.l4 lt pc105 - terminate:ctrl_alt_bksp
|
||||
lt lt pc105 - terminate:ctrl_alt_bksp
|
||||
khmer kh,us pc105 - terminate:ctrl_alt_bksp
|
||||
es-dvorak es microsoftpro dvorak terminate:ctrl_alt_bksp
|
||||
lv lv pc105 apostrophe terminate:ctrl_alt_bksp
|
||||
lv-tilde lv pc105 tilde terminate:ctrl_alt_bksp
|
||||
ge ge,us pc105 - terminate:ctrl_alt_bksp
|
||||
# The sixth column is an optional comma-separated list of RFC 4646 / BCP 47
|
||||
# language tags the row matches; used to map a firmware-reported keyboard
|
||||
# layout to a vconsole keymap. Use "-" or omit when no tags apply.
|
||||
# consolelayout xlayout xmodel xvariant xoptions bcp47
|
||||
sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp de-CH
|
||||
nl nl pc105 - terminate:ctrl_alt_bksp nl-NL,nl
|
||||
mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll mk-MK,mk
|
||||
trq tr pc105 - terminate:ctrl_alt_bksp tr-TR,tr
|
||||
uk gb pc105 - terminate:ctrl_alt_bksp en-GB
|
||||
is-latin1 is pc105 - terminate:ctrl_alt_bksp is-IS,is
|
||||
de de pc105 - terminate:ctrl_alt_bksp de-DE,de-AT,de
|
||||
la-latin1 latam pc105 - terminate:ctrl_alt_bksp es-419,es-MX,es-AR,es-CO,es-CL,es-PE,es-VE
|
||||
us us pc105+inet - terminate:ctrl_alt_bksp en-US,en
|
||||
ko kr pc105 - terminate:ctrl_alt_bksp ko-KR,ko
|
||||
ro-std ro pc105 std terminate:ctrl_alt_bksp -
|
||||
de-latin1 de pc105 - terminate:ctrl_alt_bksp -
|
||||
slovene si pc105 - terminate:ctrl_alt_bksp sl-SI,sl
|
||||
hu hu pc105 - terminate:ctrl_alt_bksp hu-HU,hu
|
||||
jp106 jp jp106 - terminate:ctrl_alt_bksp ja-JP,ja
|
||||
croat hr pc105 - terminate:ctrl_alt_bksp hr-HR,hr
|
||||
it2 it pc105 - terminate:ctrl_alt_bksp -
|
||||
hu101 hu pc105 qwerty terminate:ctrl_alt_bksp -
|
||||
sr-latin rs pc105 latin terminate:ctrl_alt_bksp sr-Latn-RS,sr-Latn
|
||||
fi fi pc105 - terminate:ctrl_alt_bksp fi-FI,fi
|
||||
fr_CH ch pc105 fr terminate:ctrl_alt_bksp fr-CH
|
||||
dk-latin1 dk pc105 - terminate:ctrl_alt_bksp da-DK,da
|
||||
fr fr pc105 - terminate:ctrl_alt_bksp fr-FR,fr
|
||||
it it pc105 - terminate:ctrl_alt_bksp it-IT,it-CH,it
|
||||
ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll uk-UA,uk
|
||||
fr-latin1 fr pc105 - terminate:ctrl_alt_bksp -
|
||||
sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp -
|
||||
be-latin1 be pc105 - terminate:ctrl_alt_bksp fr-BE,nl-BE
|
||||
dk dk pc105 - terminate:ctrl_alt_bksp -
|
||||
fr-pc fr pc105 - terminate:ctrl_alt_bksp -
|
||||
bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll bg-BG,bg
|
||||
it-ibm it pc105 - terminate:ctrl_alt_bksp -
|
||||
cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll cs-CZ,cs
|
||||
cz-qwerty cz,us pc105 qwerty, terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -
|
||||
br-abnt2 br abnt2 - terminate:ctrl_alt_bksp pt-BR
|
||||
ro ro pc105 - terminate:ctrl_alt_bksp ro-RO,ro
|
||||
us-acentos us pc105 intl terminate:ctrl_alt_bksp -
|
||||
pt-latin1 pt pc105 - terminate:ctrl_alt_bksp pt-PT,pt
|
||||
ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp -
|
||||
tj_alt-UTF8 tj pc105 - terminate:ctrl_alt_bksp tg-TJ,tg
|
||||
de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp -
|
||||
no no pc105 - terminate:ctrl_alt_bksp nb-NO,nn-NO,no
|
||||
bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -
|
||||
dvorak us pc105 dvorak terminate:ctrl_alt_bksp -
|
||||
dvorak us pc105 dvorak-alt-intl terminate:ctrl_alt_bksp -
|
||||
ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll ru-RU,ru
|
||||
cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp -
|
||||
pl2 pl pc105 - terminate:ctrl_alt_bksp pl-PL,pl
|
||||
es es pc105 - terminate:ctrl_alt_bksp es-ES,es
|
||||
ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp -
|
||||
ie ie pc105 - terminate:ctrl_alt_bksp en-IE,ga-IE,ga
|
||||
et ee pc105 - terminate:ctrl_alt_bksp et-EE,et
|
||||
sk-qwerty sk pc105 qwerty terminate:ctrl_alt_bksp -
|
||||
sk-qwertz sk pc105 - terminate:ctrl_alt_bksp sk-SK,sk
|
||||
fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp -
|
||||
fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp -
|
||||
cf ca pc105 - terminate:ctrl_alt_bksp fr-CA
|
||||
sv-latin1 se pc105 - terminate:ctrl_alt_bksp sv-SE,sv
|
||||
sr-cy rs pc105 - terminate:ctrl_alt_bksp sr-Cyrl-RS,sr-Cyrl,sr-RS,sr
|
||||
gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll el-GR,el
|
||||
by by,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll be-BY,be
|
||||
il il pc105 - terminate:ctrl_alt_bksp he-IL,he
|
||||
kazakh kz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll kk-KZ,kk
|
||||
lt.baltic lt pc105 - terminate:ctrl_alt_bksp -
|
||||
lt.l4 lt pc105 - terminate:ctrl_alt_bksp -
|
||||
lt lt pc105 - terminate:ctrl_alt_bksp lt-LT,lt
|
||||
khmer kh,us pc105 - terminate:ctrl_alt_bksp km-KH,km
|
||||
es-dvorak es microsoftpro dvorak terminate:ctrl_alt_bksp -
|
||||
lv lv pc105 apostrophe terminate:ctrl_alt_bksp lv-LV,lv
|
||||
lv-tilde lv pc105 tilde terminate:ctrl_alt_bksp -
|
||||
ge ge,us pc105 - terminate:ctrl_alt_bksp ka-GE,ka
|
||||
|
||||
@@ -578,6 +578,83 @@ int find_language_fallback(const char *lang, char **ret) {
|
||||
}
|
||||
}
|
||||
|
||||
int find_vconsole_keymap_for_bcp47(const char *tag, char **ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *fallback = NULL;
|
||||
const char *map;
|
||||
int r;
|
||||
|
||||
/* Look up a vconsole keymap by RFC 4646 / BCP 47 language tag (e.g. "de-DE") using the optional
|
||||
* sixth column of /usr/share/systemd/kbd-model-map. That column lists comma-separated tags the
|
||||
* row matches. An exact (case-insensitive) tag match returns immediately; if no exact match
|
||||
* exists, the first row whose tag matches the input's primary subtag wins. Returns 1 on match,
|
||||
* 0 otherwise. */
|
||||
|
||||
assert(tag);
|
||||
assert(ret);
|
||||
|
||||
if (isempty(tag)) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t primary_len = strcspn(tag, "-");
|
||||
if (primary_len == 0) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
map = systemd_kbd_model_map();
|
||||
f = fopen(map, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (unsigned n = 0;;) {
|
||||
_cleanup_strv_free_ char **a = NULL, **tags = NULL;
|
||||
|
||||
r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
/* The BCP 47 tag list is the optional 6th column. "-" / empty means "no tags". */
|
||||
if (strv_length(a) < 6 || isempty(a[5]) || streq(a[5], "-"))
|
||||
continue;
|
||||
|
||||
r = strv_split_full(&tags, a[5], ",", /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(t, tags) {
|
||||
if (strcaseeq(*t, tag)) {
|
||||
log_debug("Found vconsole keymap '%s' for BCP 47 tag '%s' (exact match).",
|
||||
a[0], tag);
|
||||
|
||||
r = strdup_to(ret, a[0]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!fallback && strlen(*t) == primary_len && !strchr(*t, '-') && strncaseeq(*t, tag, primary_len)) {
|
||||
fallback = strdup(a[0]);
|
||||
if (!fallback)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fallback) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Found vconsole keymap '%s' for BCP 47 tag '%s' (primary subtag match).", fallback, tag);
|
||||
*ret = TAKE_PTR(fallback);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vconsole_serialize(const VCContext *vc, const X11Context *xc, char ***env) {
|
||||
int r;
|
||||
|
||||
|
||||
@@ -39,4 +39,6 @@ typedef int (*X11VerifyCallback)(const X11Context *xc);
|
||||
int vconsole_convert_to_x11(const VCContext *vc, X11VerifyCallback verify, X11Context *ret);
|
||||
int x11_convert_to_vconsole(const X11Context *xc, VCContext *ret);
|
||||
|
||||
int find_vconsole_keymap_for_bcp47(const char *tag, char **ret);
|
||||
|
||||
int vconsole_serialize(const VCContext *vc, const X11Context *xc, char ***env);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "creds-util.h"
|
||||
#include "efivars.h"
|
||||
#include "env-file.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "vconsole-util.h"
|
||||
|
||||
typedef struct Context {
|
||||
char *keymap;
|
||||
@@ -72,6 +74,34 @@ static void context_merge_config(
|
||||
context_merge(dst, src, src_compat, font_unimap);
|
||||
}
|
||||
|
||||
static int context_read_efi(Context *c) {
|
||||
_cleanup_(context_done) Context v = {};
|
||||
_cleanup_free_ char *tag = NULL;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!is_efi_boot())
|
||||
return 0;
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderKeyboardLayout"), &tag);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to read LoaderKeyboardLayout EFI variable, ignoring: %m");
|
||||
|
||||
r = find_vconsole_keymap_for_bcp47(tag, &v.keymap);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to look up vconsole keymap for firmware tag '%s', ignoring: %m", tag);
|
||||
if (r == 0) {
|
||||
log_debug("No vconsole keymap matches firmware-provided keyboard layout '%s', ignoring.", tag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
context_merge_config(c, &v, /* src_compat= */ NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int context_read_creds(Context *c) {
|
||||
_cleanup_(context_done) Context v = {};
|
||||
int r;
|
||||
@@ -144,10 +174,13 @@ static int context_read_proc_cmdline(Context *c) {
|
||||
static void context_load_config(Context *c) {
|
||||
assert(c);
|
||||
|
||||
/* Load data from credentials (lowest priority) */
|
||||
/* Pick up the firmware-provided keyboard layout if any (lowest priority) */
|
||||
(void) context_read_efi(c);
|
||||
|
||||
/* Load data from credentials */
|
||||
(void) context_read_creds(c);
|
||||
|
||||
/* Load data from configuration file (middle priority) */
|
||||
/* Load data from configuration file */
|
||||
(void) context_read_env(c);
|
||||
|
||||
/* Let the kernel command line override /etc/vconsole.conf (highest priority) */
|
||||
|
||||
Reference in New Issue
Block a user