--- /dev/null
+@@
+expression r;
+@@
+- if (r < 0)
+- return r;
+- if (r == 0)
+- return 0;
++ if (r <= 0)
++ return r;
+@@
+expression r;
+@@
+- if (r == 0)
+- return 0;
+- if (r < 0)
+- return r;
++ if (r <= 0)
++ return r;
+@@
+expression r;
+@@
+- if (r < 0)
+- return r;
+- if (r == 0)
+- return r;
++ if (r <= 0)
++ return r;
+@@
+expression r;
+@@
+- if (r == 0)
+- return r;
+- if (r < 0)
+- return r;
++ if (r <= 0)
++ return r;
+@@
+expression r;
+@@
+- if (r < 0)
+- return r;
+- if (r > 0)
+- return r;
++ if (r != 0)
++ return r;
+@@
+expression r;
+@@
+- if (r > 0)
+- return r;
+- if (r < 0)
+- return r;
++ if (r != 0)
++ return r;
<varlistentry>
<term><varname>LoaderConfigTimeout</varname></term>
- <listitem><para>The menu time-out. Read by the boot loader. (Also, modified by it when the
- <keycap>t</keycap>/<keycap>T</keycap> keys are used, see above.)</para></listitem>
+ <term><varname>LoaderConfigTimeoutOneShot</varname></term>
+ <listitem><para>The menu time-out in seconds. Read by the boot loader. <varname>LoaderConfigTimeout</varname>
+ is maintained persistently, while <varname>LoaderConfigTimeoutOneShot</varname> is a one-time override which is
+ read once (in which case it takes precedence over <varname>LoaderConfigTimeout</varname>) and then
+ removed. <varname>LoaderConfigTimeout</varname> may be manipulated with the
+ <keycap>t</keycap>/<keycap>T</keycap> keys, see above.)</para></listitem>
</varlistentry>
<varlistentry>
loader.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>LoaderFeatures</varname></term>
+
+ <listitem><para>A set of flags indicating the features the boot loader supports. Set by the boot loader. Use
+ <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view this
+ data.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>LoaderFirmwareInfo</varname></term>
<term><varname>LoaderFirmwareType</varname></term>
return -errno;
r = cg_hybrid_unified();
- if (r < 0)
+ if (r <= 0)
return r;
- if (r == 0)
- return 0;
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
r = cg_rmdir(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
[MDASH] = "-",
[ELLIPSIS] = "...",
[MU] = "u",
+ [CHECK_MARK] = "+",
+ [CROSS_MARK] = "-",
},
/* UTF-8 */
[MDASH] = "\342\200\223", /* – */
[ELLIPSIS] = "\342\200\246", /* … */
[MU] = "\316\274", /* μ */
+ [CHECK_MARK] = "\342\234\223", /* ✓ */
+ [CROSS_MARK] = "\342\234\227", /* ✗ */
},
};
MDASH,
ELLIPSIS,
MU,
+ CHECK_MARK,
+ CROSS_MARK,
_SPECIAL_GLYPH_MAX
} SpecialGlyph;
(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);
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))
BOOLEAN editor;
BOOLEAN auto_entries;
BOOLEAN auto_firmware;
+ BOOLEAN force_menu;
UINTN console_mode;
enum console_mode_change_type console_mode_change;
} Config;
Print(L"\n--- press key ---\n\n");
console_key_read(&key, TRUE);
- Print(L"timeout: %d\n", config->timeout_sec);
+ Print(L"timeout: %u\n", config->timeout_sec);
if (config->timeout_sec_efivar >= 0)
Print(L"timeout (EFI var): %d\n", config->timeout_sec_efivar);
- Print(L"timeout (config): %d\n", config->timeout_sec_config);
+ Print(L"timeout (config): %u\n", config->timeout_sec_config);
if (config->entry_default_pattern)
Print(L"default pattern: '%s'\n", config->entry_default_pattern);
Print(L"editor: %s\n", yes_no(config->editor));
Print(L"\n");
if (efivar_get_int(L"LoaderConfigTimeout", &i) == EFI_SUCCESS)
- Print(L"LoaderConfigTimeout: %d\n", i);
+ Print(L"LoaderConfigTimeout: %u\n", i);
+
if (config->entry_oneshot)
Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot);
if (efivar_get(L"LoaderDevicePartUUID", &partstr) == EFI_SUCCESS)
UINTN sec;
EFI_STATUS err;
- config->editor = TRUE;
- config->auto_entries = TRUE;
- config->auto_firmware = TRUE;
+ *config = (Config) {
+ .editor = TRUE,
+ .auto_entries = TRUE,
+ .auto_firmware = TRUE,
+ };
err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL);
if (!EFI_ERROR(err))
err = efivar_get_int(L"LoaderConfigTimeout", &sec);
if (!EFI_ERROR(err)) {
- config->timeout_sec_efivar = sec;
+ config->timeout_sec_efivar = sec > INTN_MAX ? INTN_MAX : sec;
config->timeout_sec = sec;
} else
config->timeout_sec_efivar = -1;
+
+ err = efivar_get_int(L"LoaderConfigTimeoutOneShot", &sec);
+ if (!EFI_ERROR(err)) {
+ /* Unset variable now, after all it's "one shot". */
+ (void) efivar_set(L"LoaderConfigTimeoutOneShot", NULL, TRUE);
+
+ config->timeout_sec = sec;
+ config->force_menu = TRUE; /* force the menu when this is set */
+ }
}
static VOID config_load_entries(
}
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+ static const UINT64 loader_features =
+ (1ULL << 0) | /* I honour the LoaderConfigTimeout variable */
+ (1ULL << 1) | /* I honour the LoaderConfigTimeoutOneShot variable */
+ (1ULL << 2) | /* I honour the LoaderEntryDefault variable */
+ (1ULL << 3) | /* I honour the LoaderEntryOneShot variable */
+ (1ULL << 4) | /* I support boot counting */
+ 0;
+
_cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL;
CHAR8 *b;
UINTN size;
typestr = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
efivar_set(L"LoaderFirmwareType", typestr, FALSE);
+ (void) efivar_set_raw(&loader_guid, L"LoaderFeatures", &loader_features, sizeof(loader_features), FALSE);
+
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err)) {
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE);
- ZeroMem(&config, sizeof(Config));
config_load_defaults(&config, root_dir);
/* scan /EFI/Linux/ directory */
UINT64 osind = (UINT64)*b;
if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
- config_entry_add_call(&config, L"auto-reboot-into-firmware-ui", L"Reboot Into Firmware Interface", reboot_into_firmware);
+ config_entry_add_call(&config, L"auto-reboot-to-firmware-setup", L"Reboot Into Firmware Interface", reboot_into_firmware);
FreePool(b);
}
}
/* select entry or show menu when key is pressed or timeout is set */
- if (config.timeout_sec == 0) {
+ if (config.force_menu || config.timeout_sec > 0)
+ menu = TRUE;
+ else {
UINT64 key;
err = console_key_read(&key, FALSE);
else
menu = TRUE;
}
- } else
- menu = TRUE;
+ }
for (;;) {
ConfigEntry *entry;
uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL);
if (!menu_run(&config, &entry, loaded_image_path))
break;
+ }
- /* run special entry like "reboot" */
- if (entry->call) {
- entry->call();
- continue;
- }
+ /* run special entry like "reboot" */
+ if (entry->call) {
+ entry->call();
+ continue;
}
config_entry_bump_counters(entry, root_dir);
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) {
return 0;
}
- return 1000 * 1000 * ticks / freq;
+ return 1000UL * 1000UL * ticks / freq;
}
-EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) {
+EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) {
+ if (!v)
+ return EFI_INVALID_PARAMETER;
+
if (strcmpa(v, (CHAR8 *)"1") == 0 ||
strcmpa(v, (CHAR8 *)"yes") == 0 ||
strcmpa(v, (CHAR8 *)"y") == 0 ||
return EFI_INVALID_PARAMETER;
}
-EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, VOID *buf, UINTN size, BOOLEAN persistent) {
+EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, BOOLEAN persistent) {
UINT32 flags;
flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
if (persistent)
flags |= EFI_VARIABLE_NON_VOLATILE;
- return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf);
+ return uefi_call_wrapper(RT->SetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, flags, size, (VOID*) buf);
}
-EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) {
+EFI_STATUS efivar_set(const CHAR16 *name, const CHAR16 *value, BOOLEAN persistent) {
return efivar_set_raw(&loader_guid, name, value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent);
}
EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) {
CHAR16 str[32];
- SPrint(str, 32, L"%d", i);
+ SPrint(str, 32, L"%u", i);
return efivar_set(name, str, persistent);
}
-EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) {
+EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value) {
_cleanup_freepool_ CHAR8 *buf = NULL;
+ EFI_STATUS err;
CHAR16 *val;
UINTN size;
- EFI_STATUS err;
err = efivar_get_raw(&loader_guid, name, &buf, &size);
if (EFI_ERROR(err))
return err;
- val = StrDuplicate((CHAR16 *)buf);
+ /* Make sure there are no incomplete characters in the buffer */
+ if ((size % 2) != 0)
+ return EFI_INVALID_PARAMETER;
+
+ /* Return buffer directly if it happens to be NUL terminated already */
+ if (size >= 2 && buf[size-2] == 0 && buf[size-1] == 0) {
+ *value = (CHAR16*) buf;
+ buf = NULL;
+ return EFI_SUCCESS;
+ }
+
+ /* Make sure a terminating NUL is available at the end */
+ val = AllocatePool(size + 2);
if (!val)
return EFI_OUT_OF_RESOURCES;
+ CopyMem(val, buf, size);
+ val[size/2] = 0; /* NUL terminate */
+
*value = val;
return EFI_SUCCESS;
}
-EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
+EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i) {
_cleanup_freepool_ CHAR16 *val = NULL;
EFI_STATUS err;
return err;
}
-EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
+EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size) {
_cleanup_freepool_ CHAR8 *buf = NULL;
UINTN l;
EFI_STATUS err;
if (!buf)
return EFI_OUT_OF_RESOURCES;
- err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf);
+ err = uefi_call_wrapper(RT->GetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, NULL, &l, buf);
if (!EFI_ERROR(err)) {
*buffer = buf;
buf = NULL;
return NULL;
}
-EFI_STATUS file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size) {
+EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size) {
EFI_FILE_HANDLE handle;
_cleanup_freepool_ CHAR8 *buf = NULL;
EFI_STATUS err;
- err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL);
+ err = uefi_call_wrapper(dir->Open, 5, dir, &handle, (CHAR16*) name, EFI_FILE_MODE_READ, 0ULL);
if (EFI_ERROR(err))
return err;
return b ? L"yes" : L"no";
}
-EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b);
+EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
UINT64 ticks_read(void);
UINT64 ticks_freq(void);
UINT64 time_usec(void);
-EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent);
-EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, VOID *buf, UINTN size, BOOLEAN persistent);
+EFI_STATUS efivar_set(const CHAR16 *name, const CHAR16 *value, BOOLEAN persistent);
+EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, BOOLEAN persistent);
EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent);
VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec);
-EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value);
-EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size);
-EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i);
+EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value);
+EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size);
+EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i);
CHAR8 *strchra(CHAR8 *s, CHAR8 c);
CHAR16 *stra_to_path(CHAR8 *stra);
CHAR16 *stra_to_str(CHAR8 *stra);
-EFI_STATUS file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
+EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
static inline void FreePoolp(void *p) {
void *q = *(void**) p;
}
const EFI_GUID loader_guid;
+
+#define UINTN_MAX (~(UINTN)0)
+#define INTN_MAX ((INTN)(UINTN_MAX>>1))
log_debug("inotify event for /etc/localtime");
changed = manager_read_timezone_stat(m);
- if (changed < 0)
+ if (changed <= 0)
return changed;
- if (!changed)
- return 0;
/* Something changed, restart the watch, to ensure we watch the new /etc/localtime if it changed */
(void) manager_setup_timezone_change(m);
* It reads files named on the command line and passes them one by one into the
* fuzzer that it is compiled into. */
+/* This one was borrowed from
+ * https://github.com/google/oss-fuzz/blob/646fca1b506b056db3a60d32c4a1a7398f171c94/infra/base-images/base-runner/bad_build_check#L19
+ */
+#define MIN_NUMBER_OF_RUNS 4
+
int main(int argc, char **argv) {
int i, r;
size_t size;
}
printf("%s... ", name);
fflush(stdout);
- (void) LLVMFuzzerTestOneInput((uint8_t*)buf, size);
+ for (int j = 0; j < MIN_NUMBER_OF_RUNS; j++)
+ (void) LLVMFuzzerTestOneInput((uint8_t*)buf, size);
printf("ok\n");
}
end = m->rindex + 0;
else
end = m->rindex + c->item_size;
-
+
m->containers[m->n_containers++] = (struct bus_container) {
.enclosing = type,
.signature = TAKE_PTR(signature),
return -EBADMSG;
if (*p == 0) {
+ char *k;
size_t l;
/* We found the beginning of the signature
p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
return -EBADMSG;
- if (free_and_strndup(&m->root_container.signature,
- p + 1 + 1, l - 2) < 0)
+ k = memdup_suffix0(p + 1 + 1, l - 2);
+ if (!k)
return -ENOMEM;
+
+ free_and_replace(m->root_container.signature, k);
break;
}
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;
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) {
#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"
#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"
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);
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";
}
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");
}
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),
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),
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);
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
+ <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
</action>
<action id="org.freedesktop.login1.set-wall-message">
a = dns_resource_key_name(rr->key);
r = dns_name_parent(&a); /* strip off hash */
- if (r < 0)
+ if (r <= 0)
return r;
- if (r == 0)
- return 0;
b = dns_resource_key_name(nsec3->key);
r = dns_name_parent(&b); /* strip off hash */
- if (r < 0)
+ if (r <= 0)
return r;
- if (r == 0)
- return 0;
/* Make sure both have the same parent */
return dns_name_equal(a, b);
for (;;) {
next_closer = name;
r = dns_name_parent(&name);
- if (r < 0)
+ if (r <= 0)
return r;
- if (r == 0)
- return 0;
r = dns_name_equal(name, source);
if (r < 0)
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,
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;
-
- r = efi_get_variable(vendor, name, NULL, &s, &ss);
- if (r < 0)
- return r;
+int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v) {
+ _cleanup_free_ char16_t *u16 = NULL;
- 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) {
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;
/* 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? */
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)
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;
+}
#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);
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);
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) {
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;
}
return -EOPNOTSUPP;
}
+static inline int efi_loader_get_features(uint64_t *ret) {
+ return -EOPNOTSUPP;
+}
+
#endif
char *efi_tilt_backslashes(char *s);
#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__);
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[]) {