diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 9ad51a1972..7e479d605a 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -369,6 +369,8 @@ const char *special_glyph(SpecialGlyph code) { [MDASH] = "-", [ELLIPSIS] = "...", [MU] = "u", + [CHECK_MARK] = "+", + [CROSS_MARK] = "-", }, /* UTF-8 */ @@ -383,6 +385,8 @@ const char *special_glyph(SpecialGlyph code) { [MDASH] = "\342\200\223", /* – */ [ELLIPSIS] = "\342\200\246", /* … */ [MU] = "\316\274", /* μ */ + [CHECK_MARK] = "\342\234\223", /* ✓ */ + [CROSS_MARK] = "\342\234\227", /* ✗ */ }, }; diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index 14beece6d8..ea624e9908 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -49,6 +49,8 @@ typedef enum { MDASH, ELLIPSIS, MU, + CHECK_MARK, + CROSS_MARK, _SPECIAL_GLYPH_MAX } SpecialGlyph; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 7a20965b6a..427faf8b24 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -968,14 +968,28 @@ static int verb_status(int argc, char *argv[], void *userdata) { (void) pager_open(arg_pager_flags); if (is_efi_boot()) { + static const struct { + uint64_t flag; + const char *name; + } 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" }, + }; + _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL; sd_id128_t loader_part_uuid = SD_ID128_NULL; + uint64_t loader_features = 0; + size_t i; read_loader_efi_var("LoaderFirmwareType", &fw_type); read_loader_efi_var("LoaderFirmwareInfo", &fw_info); read_loader_efi_var("LoaderInfo", &loader); read_loader_efi_var("StubInfo", &stub); read_loader_efi_var("LoaderImageIdentifier", &loader_path); + (void) efi_loader_get_features(&loader_features); if (loader_path) efi_tilt_backslashes(loader_path); @@ -992,6 +1006,20 @@ static int verb_status(int argc, char *argv[], void *userdata) { printf("Current Boot Loader:\n"); printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal()); + + for (i = 0; i < ELEMENTSOF(flags); i++) { + + if (i == 0) + printf(" Features: "); + else + printf(" "); + + if (FLAGS_SET(loader_features, flags[i].flag)) + printf("%s%s%s %s\n", ansi_highlight_green(), special_glyph(CHECK_MARK), ansi_normal(), flags[i].name); + else + printf("%s%s%s %s\n", ansi_highlight_red(), special_glyph(CROSS_MARK), ansi_normal(), flags[i].name); + } + if (stub) printf(" Stub: %s\n", stub); if (!sd_id128_is_null(loader_part_uuid)) diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index fd4be681a5..b70777292e 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -39,7 +39,7 @@ UINT64 ticks_freq(VOID) { uefi_call_wrapper(BS->Stall, 1, 1000); ticks_end = ticks_read(); - return (ticks_end - ticks_start) * 1000; + return (ticks_end - ticks_start) * 1000UL; } UINT64 time_usec(VOID) { @@ -56,7 +56,7 @@ UINT64 time_usec(VOID) { return 0; } - return 1000 * 1000 * ticks / freq; + return 1000UL * 1000UL * ticks / freq; } EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) { diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 24f7c1439f..2bab2fd2f5 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -566,6 +566,17 @@ int manager_spawn_autovt(Manager *m, unsigned vtnr) { return 0; } +bool manager_is_lid_closed(Manager *m) { + Iterator i; + Button *b; + + HASHMAP_FOREACH(b, m->buttons, i) + if (b->lid_closed) + return true; + + return false; +} + static bool manager_is_docked(Manager *m) { Iterator i; Button *b; @@ -670,15 +681,13 @@ bool manager_is_docked_or_external_displays(Manager *m) { bool manager_is_on_external_power(void) { int r; - /* For now we only check for AC power, but 'external power' can apply - * to anything that isn't an internal battery */ + /* For now we only check for AC power, but 'external power' can apply to anything that isn't an internal + * battery */ r = on_ac_power(); if (r < 0) log_warning_errno(r, "Failed to read AC power status: %m"); - else if (r > 0) - return true; - return false; + return r != 0; /* Treat failure as 'on AC' */ } bool manager_all_buttons_ignored(Manager *m) { diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 927e304a0c..c0dafa03ef 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -14,6 +14,7 @@ #include "bus-error.h" #include "bus-unit-util.h" #include "bus-util.h" +#include "cgroup-util.h" #include "device-util.h" #include "dirent-util.h" #include "efivars.h" @@ -26,7 +27,6 @@ #include "mkdir.h" #include "path-util.h" #include "process-util.h" -#include "cgroup-util.h" #include "selinux-util.h" #include "sleep-config.h" #include "special.h" @@ -274,6 +274,8 @@ static int property_get_scheduled_shutdown( static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction); static BUS_DEFINE_PROPERTY_GET(property_get_docked, "b", Manager, manager_is_docked_or_external_displays); +static BUS_DEFINE_PROPERTY_GET(property_get_lid_closed, "b", Manager, manager_is_lid_closed); +static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_on_external_power, "b", manager_is_on_external_power); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_compat_user_tasks_max, "t", CGROUP_LIMIT_MAX); static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "t", Hashmap *, (uint64_t) hashmap_size); @@ -2265,11 +2267,13 @@ static int method_can_shutdown_or_sleep( if (r < 0) return r; - if (r > 0 && !result) - result = "yes"; - else if (challenge && (!result || streq(result, "yes"))) - result = "challenge"; - else + if (r > 0) { + if (!result) + result = "yes"; + } else if (challenge) { + if (!result || streq(result, "yes")) + result = "challenge"; + } else result = "no"; } @@ -2456,7 +2460,7 @@ static int method_can_reboot_to_firmware_setup( r = efi_reboot_to_firmware_supported(); if (r < 0) { if (r != -EOPNOTSUPP) - log_warning_errno(errno, "Failed to determine whether reboot to firmware is supported: %m"); + log_warning_errno(r, "Failed to determine whether reboot to firmware is supported: %m"); return sd_bus_reply_method_return(message, "s", "na"); } @@ -2645,7 +2649,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, 0), SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -2666,6 +2670,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0), SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0), SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0), + SD_BUS_PROPERTY("LidClosed", "b", property_get_lid_closed, 0, 0), + SD_BUS_PROPERTY("OnExternalPower", "b", property_get_on_external_power, 0, 0), SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectorySize", "t", NULL, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/login/logind.h b/src/login/logind.h index 5398cca8c4..7b774f49e0 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -146,6 +146,7 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t); int manager_get_user_by_pid(Manager *m, pid_t pid, User **user); int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session); +bool manager_is_lid_closed(Manager *m); bool manager_is_docked_or_external_displays(Manager *m); bool manager_is_on_external_power(void); bool manager_all_buttons_ignored(Manager *m); diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy index 78bee24b05..5ee62ab5b4 100644 --- a/src/login/org.freedesktop.login1.policy +++ b/src/login/org.freedesktop.login1.policy @@ -345,6 +345,7 @@ auth_admin_keep yes + org.freedesktop.login1.reboot diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 7a9754096c..fbed9027c1 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -246,6 +246,24 @@ int efi_get_variable( return 0; } +int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) { + _cleanup_free_ void *s = NULL; + size_t ss = 0; + int r; + char *x; + + r = efi_get_variable(vendor, name, NULL, &s, &ss); + if (r < 0) + return r; + + x = utf16_to_utf8(s, ss); + if (!x) + return -ENOMEM; + + *p = x; + return 0; +} + int efi_set_variable( sd_id128_t vendor, const char *name, @@ -326,22 +344,14 @@ finish: return r; } -int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) { - _cleanup_free_ void *s = NULL; - size_t ss = 0; - int r; - char *x; +int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v) { + _cleanup_free_ char16_t *u16 = NULL; - r = efi_get_variable(vendor, name, NULL, &s, &ss); - if (r < 0) - return r; - - x = utf16_to_utf8(s, ss); - if (!x) + u16 = utf8_to_utf16(v, strlen(v)); + if (!u16) return -ENOMEM; - *p = x; - return 0; + return efi_set_variable(vendor, name, u16, (char16_strlen(u16) + 1) * sizeof(char16_t)); } static size_t utf16_size(const uint16_t *s) { @@ -761,6 +771,16 @@ int efi_loader_get_device_part_uuid(sd_id128_t *u) { return 0; } +bool efi_loader_entry_name_valid(const char *s) { + if (isempty(s)) + return false; + + if (strlen(s) > FILENAME_MAX) /* Make sure entry names fit in filenames */ + return false; + + return in_charset(s, ALPHANUMERICAL "-"); +} + int efi_loader_get_entries(char ***ret) { _cleanup_free_ char16_t *entries = NULL; _cleanup_strv_free_ char **l = NULL; @@ -779,7 +799,7 @@ int efi_loader_get_entries(char ***ret) { /* The variable contains a series of individually NUL terminated UTF-16 strings. */ for (i = 0, start = 0;; i++) { - char *decoded; + _cleanup_free_ char *decoded = NULL; bool end; /* Is this the end of the variable's data? */ @@ -795,9 +815,12 @@ int efi_loader_get_entries(char ***ret) { if (!decoded) return -ENOMEM; - r = strv_consume(&l, decoded); - if (r < 0) - return r; + if (efi_loader_entry_name_valid(decoded)) { + r = strv_consume(&l, TAKE_PTR(decoded)); + if (r < 0) + return r; + } else + log_debug("Ignoring invalid loader entry '%s'.", decoded); /* We reached the end of the variable */ if (end) @@ -822,3 +845,53 @@ char *efi_tilt_backslashes(char *s) { return s; } + +int efi_loader_get_features(uint64_t *ret) { + _cleanup_free_ void *v = NULL; + size_t s; + int r; + + if (!is_efi_boot()) { + *ret = 0; + return 0; + } + + r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderFeatures", NULL, &v, &s); + if (r == -ENOENT) { + _cleanup_free_ char *info = NULL; + + /* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */ + r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info); + if (r < 0) { + if (r != -ENOENT) + return r; + + /* Variable not set, definitely means not systemd-boot */ + + } else if (first_word(info, "systemd-boot")) { + + /* An older systemd-boot version. Let's hardcode the feature set, since it was pretty + * static in all its versions. */ + + *ret = EFI_LOADER_FEATURE_CONFIG_TIMEOUT | + EFI_LOADER_FEATURE_ENTRY_DEFAULT | + EFI_LOADER_FEATURE_ENTRY_ONESHOT; + + return 0; + } + + /* No features supported */ + *ret = 0; + return 0; + } + if (r < 0) + return r; + + if (s != sizeof(uint64_t)) { + log_debug("LoaderFeatures EFI variable doesn't have the right size."); + return -EINVAL; + } + + memcpy(ret, v, sizeof(uint64_t)); + return 0; +} diff --git a/src/shared/efivars.h b/src/shared/efivars.h index 9b5ab39fee..92670c82c7 100644 --- a/src/shared/efivars.h +++ b/src/shared/efivars.h @@ -18,6 +18,12 @@ #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 +#define EFI_LOADER_FEATURE_CONFIG_TIMEOUT (UINT64_C(1) << 0) +#define EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT (UINT64_C(1) << 1) +#define EFI_LOADER_FEATURE_ENTRY_DEFAULT (UINT64_C(1) << 2) +#define EFI_LOADER_FEATURE_ENTRY_ONESHOT (UINT64_C(1) << 3) +#define EFI_LOADER_FEATURE_BOOT_COUNTING (UINT64_C(1) << 4) + #if ENABLE_EFI bool is_efi_boot(void); @@ -28,8 +34,9 @@ int efi_get_reboot_to_firmware(void); int efi_set_reboot_to_firmware(bool value); int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size); -int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size); int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p); +int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size); +int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *p); int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active); int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, const char *path); @@ -43,6 +50,10 @@ int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader); int efi_loader_get_entries(char ***ret); +bool efi_loader_entry_name_valid(const char *s); + +int efi_loader_get_features(uint64_t *ret); + #else static inline bool is_efi_boot(void) { @@ -73,11 +84,15 @@ static inline int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t return -EOPNOTSUPP; } +static inline int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) { + return -EOPNOTSUPP; +} + static inline int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size) { return -EOPNOTSUPP; } -static inline int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) { +static inline int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *p) { return -EOPNOTSUPP; } @@ -117,6 +132,10 @@ static inline int efi_loader_get_entries(char ***ret) { return -EOPNOTSUPP; } +static inline int efi_loader_get_features(uint64_t *ret) { + return -EOPNOTSUPP; +} + #endif char *efi_tilt_backslashes(char *s); diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 3634534782..6d0f24eeea 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -65,7 +65,7 @@ static void test_keymaps(void) { #define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x)) static void dump_special_glyphs(void) { - assert_cc(MU + 1 == _SPECIAL_GLYPH_MAX); + assert_cc(CROSS_MARK + 1 == _SPECIAL_GLYPH_MAX); log_info("/* %s */", __func__); @@ -80,6 +80,9 @@ static void dump_special_glyphs(void) { dump_glyph(ARROW); dump_glyph(MDASH); dump_glyph(ELLIPSIS); + dump_glyph(MU); + dump_glyph(CHECK_MARK); + dump_glyph(CROSS_MARK); } int main(int argc, char *argv[]) {