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[]) {