mirror of
https://github.com/systemd/systemd
synced 2026-04-24 16:04:51 +02:00
Compare commits
19 Commits
2df5a7d3f1
...
c0da575a0e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0da575a0e | ||
|
|
197be5324e | ||
|
|
598e431500 | ||
|
|
18a02561f1 | ||
|
|
3e3c49cbe7 | ||
|
|
2cf120f7cf | ||
|
|
42ac3bf1a3 | ||
|
|
c7749367e3 | ||
|
|
b1d723228e | ||
|
|
901fa9a4c9 | ||
|
|
04d1fbd564 | ||
|
|
20742f92c1 | ||
|
|
e12335ba60 | ||
|
|
db9eabd675 | ||
|
|
8214758bd5 | ||
|
|
5672bdd341 | ||
|
|
61ec7beaf5 | ||
|
|
036a8d503f | ||
|
|
957b242319 |
38
TODO
38
TODO
@ -78,6 +78,44 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* systemd creds hookup with qemu fw_cfg. (Quite possibly might not need any
|
||||
code at all, given the fw_cfg stuff are just files, but we should then
|
||||
document how to use it). Goal: provide symmetric ways to pass creds to nspawn
|
||||
containers and qemu VMs. (maybe also pick up env vars from fw_cfg?)
|
||||
|
||||
* beef up sd_notify() to support AV_VSOCK in $NOTIFY_SOCKET, so that VM
|
||||
managers can get ready notifications from VMs, just like container managers
|
||||
from their payload. Also pick up address from qemu/fw_cfg if set there.
|
||||
(which has benefits, given SecureBoot and kernel cmdline are not necessarily
|
||||
friends.)
|
||||
|
||||
* mirroring this: maybe support binding to AV_VSOCK in Type=notify services,
|
||||
then passing $NOTIFY_SOCKET and $NOTIFY_GUESTCID with PID1's cid (typically
|
||||
fixed to "2", i.e. the official host cid) and the expected guest cid, for the
|
||||
two sides of the channe. The latter env var could then be used in an
|
||||
appropriate qemu cmdline. That way qemu payloads could talk sd_notify()
|
||||
directly to host service manager.
|
||||
|
||||
* maybe write a tool that binds an AF_VFSOCK socket, then invokes qemu,
|
||||
extending the command line to enable vsock on the VM, and using fw_cfg to
|
||||
configure socket address.
|
||||
|
||||
* sd-boot: rework random seed handling following recent kernel changes: always
|
||||
pass seed to kernel, but credit only if secure boot is used
|
||||
|
||||
* sd-boot: hash data from GetNextHighMonotonicCount() into updated random seed,
|
||||
so that we might even open up up the random seed logic to non-SecureBoot
|
||||
systems?
|
||||
|
||||
* sd-boot: add menu item for shutdown? or hotkey?
|
||||
|
||||
* sd-device has an API to create an sd_device object from a device id, but has
|
||||
no api to query the device id
|
||||
|
||||
* sd-device should return the devnum type (i.e. 'b' or 'c') via some API for an
|
||||
sd_device object, so that data passed into sd_device_new_from_devnum() can
|
||||
also be queried.
|
||||
|
||||
* udevadm: a new "tree" verb that shows tree of devices as syspath hierarchy,
|
||||
along with their properties. uninitialized devices should be greyed out.
|
||||
|
||||
|
||||
143
man/bootctl.xml
143
man/bootctl.xml
@ -46,12 +46,14 @@
|
||||
<varlistentry>
|
||||
<term><option>status</option></term>
|
||||
|
||||
<listitem><para>Shows brief information about the system firmware, the boot loader that was used to boot the
|
||||
system, the boot loaders currently available in the ESP, the boot loaders listed in the firmware's list of boot
|
||||
loaders and the current default boot loader entry. If no command is specified, this is the implied
|
||||
default.</para></listitem>
|
||||
<listitem><para>Shows brief information about the system firmware, the boot loader that was used to
|
||||
boot the system, the boot loaders currently available in the ESP, the boot loaders listed in the
|
||||
firmware's list of boot loaders and the current default boot loader entry. If no command is
|
||||
specified, this is the implied default.</para>
|
||||
|
||||
<para>See the example below for details of the output.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>reboot-to-firmware</option> <optional><replaceable>BOOL</replaceable></optional></term>
|
||||
@ -59,20 +61,20 @@
|
||||
<listitem><para>Query or set the "Reboot-Into-Firmware-Setup" flag of the EFI firmware. Takes a
|
||||
boolean argument which controls whether to show the firmware setup on next system reboot. If the
|
||||
argument is omitted shows the current status of the flag, or whether the flag is supported. This
|
||||
controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more
|
||||
low-level and allows setting the flag independently from actually requesting a
|
||||
reboot.</para></listitem>
|
||||
controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more low-level
|
||||
and allows setting the flag independently from actually requesting a reboot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>systemd-efi-options</option> <optional><replaceable>STRING</replaceable></optional></term>
|
||||
|
||||
<listitem><para>When called without the optional argument, prints the current value of the
|
||||
<literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
|
||||
variable to that value. See
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for the meaning of that variable.</para></listitem>
|
||||
<literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the variable to
|
||||
that value. See
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> for the
|
||||
meaning of that variable.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -84,17 +86,16 @@
|
||||
<command>systemd-boot</command>.</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>list</option></term>
|
||||
|
||||
<listitem><para>Shows all available boot loader entries implementing the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, as well as any
|
||||
other entries discovered or automatically generated by a boot loader implementing the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
|
||||
Interface</ulink>.</para>
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>.
|
||||
JSON output may be requested with <option>--json=</option>.</para>
|
||||
|
||||
<para>JSON output may be requested with <option>--json=</option>.</para>
|
||||
<para>See the example below for details of the output.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -104,9 +105,9 @@
|
||||
|
||||
<listitem><para>Sets the default boot loader entry. Takes a single boot loader entry ID string or a glob
|
||||
pattern as argument. The <option>set-oneshot</option> command will set the default entry only for the next boot,
|
||||
the <option>set-default</option> will set it persistently for all future boots.</para></listitem>
|
||||
the <option>set-default</option> will set it persistently for all future boots.</para>
|
||||
|
||||
<listitem><para>Optionally, the boot loader entry ID may be specified as one of: <option>@default</option>,
|
||||
<para>Optionally, the boot loader entry ID may be specified as one of: <option>@default</option>,
|
||||
<option>@oneshot</option> or <option>@current</option>, which correspond to the current default boot loader
|
||||
entry for all future boots, the current default boot loader entry for the next boot, and the currently booted
|
||||
boot loader entry. These special IDs are resolved to the current values of the EFI variables
|
||||
@ -137,7 +138,6 @@
|
||||
disables the timeout while always showing the menu. When an empty string ("") is specified the
|
||||
bootloader will revert to its default menu timeout.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@ -347,6 +347,111 @@
|
||||
the Extended Boot Loader partition.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<example>
|
||||
<title>Output from <command>status</command> and <command>list</command></title>
|
||||
|
||||
<programlisting>$ <command>bootctl status</command>
|
||||
System:
|
||||
Firmware: UEFI 2.40 (<replaceable>firmware-version</replaceable>) ← firmware vendor and version
|
||||
Secure Boot: disabled (setup) ← secure boot status
|
||||
TPM2 Support: yes
|
||||
Boot into FW: supported ← does the firmware support booting into itself
|
||||
|
||||
Current Boot Loader: ← details about sd-boot or another boot loader
|
||||
Product: systemd-boot <replaceable>version</replaceable> implementing the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>
|
||||
Features: ✓ Boot counting
|
||||
✓ Menu timeout control
|
||||
✓ One-shot menu timeout control
|
||||
✓ Default entry control
|
||||
✓ One-shot entry control
|
||||
✓ Support for XBOOTLDR partition
|
||||
✓ Support for passing random seed to OS
|
||||
✓ Load drop-in drivers
|
||||
✓ Boot loader sets ESP information
|
||||
ESP: /dev/disk/by-partuuid/01234567-89ab-cdef-dead-beef00000000
|
||||
File: └─/EFI/systemd/systemd-bootx64.efi
|
||||
|
||||
Random Seed: ← random seed used for entropy in early boot
|
||||
Passed to OS: yes
|
||||
System Token: set
|
||||
Exists: yes
|
||||
|
||||
Available Boot Loaders on ESP:
|
||||
ESP: /boot/efi (/dev/disk/by-partuuid/01234567-89ab-cdef-dead-beef00000000)
|
||||
File: └─/EFI/systemd/systemd-bootx64.efi (systemd-boot 251
|
||||
File: └─/EFI/BOOT/BOOTX64.EFI (systemd-boot 251
|
||||
|
||||
Boot Loaders Listed in EFI Variables:
|
||||
Title: Linux Boot Manager
|
||||
ID: 0x0001
|
||||
Status: active, boot-order
|
||||
Partition: /dev/disk/by-partuuid/…
|
||||
File: └─/EFI/systemd/systemd-bootx64.efi
|
||||
|
||||
Title: Fedora
|
||||
ID: 0x0000
|
||||
Status: active, boot-order
|
||||
Partition: /dev/disk/by-partuuid/…
|
||||
File: └─/EFI/fedora/shimx64.efi
|
||||
|
||||
Title: Linux-Firmware-Updater
|
||||
ID: 0x0002
|
||||
Status: active, boot-order
|
||||
Partition: /dev/disk/by-partuuid/…
|
||||
File: └─/EFI/fedora/fwupdx64.efi
|
||||
|
||||
Boot Loader Entries:
|
||||
$BOOT: /boot/efi (/dev/disk/by-partuuid/01234567-89ab-cdef-dead-beef00000000)
|
||||
|
||||
Default Boot Loader Entry:
|
||||
type: Boot Loader Specification Type #1 (.conf)
|
||||
title: Fedora Linux 36 (Workstation Edition)
|
||||
id: …
|
||||
source: /boot/efi/loader/entries/<replaceable>entry-token</replaceable>-<replaceable>kernel-version</replaceable>.conf
|
||||
version: <replaceable>kernel-version</replaceable>
|
||||
machine-id: …
|
||||
linux: /<replaceable>entry-token</replaceable>/<replaceable>kernel-version</replaceable>/linux
|
||||
initrd: /<replaceable>entry-token</replaceable>/<replaceable>kernel-version</replaceable>/initrd
|
||||
options: root=…
|
||||
</programlisting>
|
||||
|
||||
<programlisting>$ <command>bootctl list</command>
|
||||
Boot Loader Entries:
|
||||
type: Boot Loader Specification Type #1 (.conf)
|
||||
title: Fedora Linux 36 (Workstation Edition) (default) (selected)
|
||||
id: …
|
||||
source: /boot/efi/loader/entries/<replaceable>entry-token</replaceable>-<replaceable>kernel-version</replaceable>.conf
|
||||
version: <replaceable>kernel-version</replaceable>
|
||||
machine-id: …
|
||||
linux: /<replaceable>entry-token</replaceable>/<replaceable>kernel-version</replaceable>/linux
|
||||
initrd: /<replaceable>entry-token</replaceable>/<replaceable>kernel-version</replaceable>/initrd
|
||||
options: root=…
|
||||
|
||||
type: Boot Loader Specification Type #2 (.efi)
|
||||
title: Fedora Linux 35 (Workstation Edition)
|
||||
id: …
|
||||
source: /boot/efi/EFI/Linux/fedora-<replaceable>kernel-version</replaceable>.efi
|
||||
version: <replaceable>kernel-version</replaceable>
|
||||
machine-id: …
|
||||
linux: /EFI/Linux/fedora-<replaceable>kernel-version</replaceable>.efi
|
||||
options: root=…
|
||||
|
||||
type: Automatic
|
||||
title: Reboot Into Firmware Interface
|
||||
id: auto-reboot-to-firmware-setup
|
||||
source: /sys/firmware/efi/efivars/LoaderEntries-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
|
||||
</programlisting>
|
||||
|
||||
<para>In the listing, <literal>(default)</literal> specifies the entry that will be
|
||||
used by default, and <literal>(selected)</literal> specifies the entry that was
|
||||
selected the last time (i.e. is currently running).</para>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
|
||||
@ -115,7 +115,7 @@ static int acquire_esp(
|
||||
free_and_replace(arg_esp_path, np);
|
||||
log_debug("Using EFI System Partition at %s.", arg_esp_path);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_xbootldr(
|
||||
@ -583,6 +583,35 @@ static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type, BootEntryType);
|
||||
|
||||
static int boot_config_load_and_select(
|
||||
BootConfig *config,
|
||||
const char *esp_path,
|
||||
dev_t esp_devid,
|
||||
const char *xbootldr_path,
|
||||
dev_t xbootldr_devid) {
|
||||
|
||||
_cleanup_strv_free_ char **efi_entries = NULL;
|
||||
int r;
|
||||
|
||||
/* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
|
||||
* find the same entries twice. */
|
||||
bool same = esp_path && xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid);
|
||||
|
||||
r = boot_config_load(config, esp_path, same ? NULL : xbootldr_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = efi_loader_get_entries(&efi_entries);
|
||||
if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
|
||||
log_debug_errno(r, "Boot loader reported no entries.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
|
||||
else
|
||||
(void) boot_config_augment_from_loader(config, efi_entries, /* only_auto= */ false);
|
||||
|
||||
return boot_config_select_special_entries(config);
|
||||
}
|
||||
|
||||
static int boot_entry_show(
|
||||
const BootEntry *e,
|
||||
bool show_as_default,
|
||||
@ -682,16 +711,17 @@ static int boot_entry_show(
|
||||
}
|
||||
|
||||
static int status_entries(
|
||||
const BootConfig *config,
|
||||
const char *esp_path,
|
||||
sd_id128_t esp_partition_uuid,
|
||||
const char *xbootldr_path,
|
||||
sd_id128_t xbootldr_partition_uuid) {
|
||||
|
||||
_cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
|
||||
sd_id128_t dollar_boot_partition_uuid;
|
||||
const char *dollar_boot_path;
|
||||
int r;
|
||||
|
||||
assert(config);
|
||||
assert(esp_path || xbootldr_path);
|
||||
|
||||
if (xbootldr_path) {
|
||||
@ -709,21 +739,13 @@ static int status_entries(
|
||||
SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
|
||||
printf("\n\n");
|
||||
|
||||
r = boot_config_load(&config, esp_path, xbootldr_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = boot_config_select_special_entries(&config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (config.default_entry < 0)
|
||||
printf("%zu entries, no entry could be determined as default.\n", config.n_entries);
|
||||
if (config->default_entry < 0)
|
||||
printf("%zu entries, no entry could be determined as default.\n", config->n_entries);
|
||||
else {
|
||||
printf("Default Boot Loader Entry:\n");
|
||||
|
||||
r = boot_entry_show(
|
||||
boot_config_default_entry(&config),
|
||||
boot_config_default_entry(config),
|
||||
/* show_as_default= */ false,
|
||||
/* show_as_selected= */ false,
|
||||
/* show_discovered= */ false);
|
||||
@ -1593,13 +1615,9 @@ static void print_yes_no_line(bool first, bool good, const char *name) {
|
||||
name);
|
||||
}
|
||||
|
||||
static int are_we_installed(void) {
|
||||
static int are_we_installed(const char *esp_path) {
|
||||
int r;
|
||||
|
||||
r = acquire_esp(/* privileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Tests whether systemd-boot is installed. It's not obvious what to use as check here: we could
|
||||
* check EFI variables, we could check what binary /EFI/BOOT/BOOT*.EFI points to, or whether the
|
||||
* loader entries directory exists. Here we opted to check whether /EFI/systemd/ is non-empty, which
|
||||
@ -1614,7 +1632,7 @@ static int are_we_installed(void) {
|
||||
* → It specifically checks for systemd-boot, not for other boot loaders (which a check for
|
||||
* /boot/loader/entries would do). */
|
||||
|
||||
_cleanup_free_ char *p = path_join(arg_esp_path, "/EFI/systemd/");
|
||||
_cleanup_free_ char *p = path_join(esp_path, "/EFI/systemd/");
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
@ -1645,7 +1663,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid, &xbootldr_devid);
|
||||
if (arg_print_dollar_boot_path) {
|
||||
if (r == -EACCES)
|
||||
return log_error_errno(r, "Failed to determine XBOOTLDR location: %m");
|
||||
return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1659,8 +1677,8 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
if (arg_print_esp_path || arg_print_dollar_boot_path)
|
||||
return 0;
|
||||
|
||||
r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
|
||||
* can show */
|
||||
r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
|
||||
* show what we can show */
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
@ -1776,16 +1794,20 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (arg_esp_path || arg_xbootldr_path) {
|
||||
/* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would find the same entries twice */
|
||||
bool same = arg_esp_path && arg_xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid);
|
||||
_cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
|
||||
|
||||
k = status_entries(
|
||||
arg_esp_path,
|
||||
esp_uuid,
|
||||
same ? NULL : arg_xbootldr_path,
|
||||
same ? SD_ID128_NULL : xbootldr_uuid);
|
||||
k = boot_config_load_and_select(&config,
|
||||
arg_esp_path, esp_devid,
|
||||
arg_xbootldr_path, xbootldr_devid);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
else {
|
||||
k = status_entries(&config,
|
||||
arg_esp_path, esp_uuid,
|
||||
arg_xbootldr_path, xbootldr_uuid);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
@ -1793,17 +1815,17 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
||||
|
||||
static int verb_list(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
|
||||
_cleanup_strv_free_ char **efi_entries = NULL;
|
||||
dev_t esp_devid = 0, xbootldr_devid = 0;
|
||||
int r;
|
||||
|
||||
/* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
|
||||
* off logging about access errors and turn off potentially privileged device probing. Here we're interested in
|
||||
* the latter but not the former, hence request the mode, and log about EACCES. */
|
||||
/* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
|
||||
* things: turn off logging about access errors and turn off potentially privileged device probing.
|
||||
* Here we're interested in the latter but not the former, hence request the mode, and log about
|
||||
* EACCES. */
|
||||
|
||||
r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL, &esp_devid);
|
||||
if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
|
||||
return log_error_errno(r, "Failed to determine ESP: %m");
|
||||
return log_error_errno(r, "Failed to determine ESP location: %m");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1813,22 +1835,7 @@ static int verb_list(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would find the same entries twice */
|
||||
bool same = arg_esp_path && arg_xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid);
|
||||
|
||||
r = boot_config_load(&config, arg_esp_path, same ? NULL : arg_xbootldr_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = efi_loader_get_entries(&efi_entries);
|
||||
if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
|
||||
log_debug_errno(r, "Boot loader reported no entries.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
|
||||
else
|
||||
(void) boot_config_augment_from_loader(&config, efi_entries, /* only_auto= */ false);
|
||||
|
||||
r = boot_config_select_special_entries(&config);
|
||||
r = boot_config_load_and_select(&config, arg_esp_path, esp_devid, arg_xbootldr_path, xbootldr_devid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -2063,7 +2070,7 @@ static int verb_install(int argc, char *argv[], void *userdata) {
|
||||
|
||||
if (!install) {
|
||||
/* If we are updating, don't do anything if sd-boot wasn't actually installed. */
|
||||
r = are_we_installed();
|
||||
r = are_we_installed(arg_esp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
@ -2209,7 +2216,11 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
static int verb_is_installed(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
r = are_we_installed();
|
||||
r = acquire_esp(/* privileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = are_we_installed(arg_esp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@ -17,14 +17,18 @@
|
||||
|
||||
static void test_sd_device_one(sd_device *d) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||
const char *syspath, *sysname, *subsystem = NULL, *id, *devname, *val;
|
||||
const char *syspath, *sysname, *subsystem = NULL, *devname, *val;
|
||||
bool is_block = false;
|
||||
dev_t devnum;
|
||||
usec_t usec;
|
||||
int i, r;
|
||||
int ifindex, r;
|
||||
|
||||
assert_se(sd_device_get_syspath(d, &syspath) >= 0);
|
||||
assert_se(path_startswith(syspath, "/sys"));
|
||||
assert_se(sd_device_get_sysname(d, &sysname) >= 0);
|
||||
|
||||
log_info("%s(%s)", __func__, syspath);
|
||||
|
||||
assert_se(sd_device_new_from_syspath(&dev, syspath) >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
@ -35,10 +39,34 @@ static void test_sd_device_one(sd_device *d) {
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
|
||||
assert_se(sd_device_get_sysname(d, &sysname) >= 0);
|
||||
r = sd_device_get_ifindex(d, &ifindex);
|
||||
if (r >= 0) {
|
||||
assert_se(ifindex > 0);
|
||||
|
||||
r = sd_device_new_from_ifindex(&dev, ifindex);
|
||||
if (r == -ENODEV)
|
||||
log_device_warning_errno(d, r,
|
||||
"Failed to create sd-device object from ifindex %i. "
|
||||
"Maybe running on a non-host network namespace.", ifindex);
|
||||
else {
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
}
|
||||
|
||||
/* This does not require the interface really exists on the network namespace.
|
||||
* Hence, this should always succeed. */
|
||||
assert_se(sd_device_new_from_ifname(&dev, sysname) >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
} else
|
||||
assert_se(r == -ENOENT);
|
||||
|
||||
r = sd_device_get_subsystem(d, &subsystem);
|
||||
if (r >= 0) {
|
||||
const char *name;
|
||||
const char *name, *id;
|
||||
|
||||
if (streq(subsystem, "drivers"))
|
||||
name = strjoina(d->driver_subsystem, ":", sysname);
|
||||
@ -48,6 +76,31 @@ static void test_sd_device_one(sd_device *d) {
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
|
||||
/* The device ID depends on subsystem. */
|
||||
assert_se(device_get_device_id(d, &id) >= 0);
|
||||
r = sd_device_new_from_device_id(&dev, id);
|
||||
if (r == -ENODEV && ifindex > 0)
|
||||
log_device_warning_errno(d, r,
|
||||
"Failed to create sd-device object from device ID \"%s\". "
|
||||
"Maybe running on a non-host network namespace.", id);
|
||||
else {
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
}
|
||||
|
||||
/* These require udev database, and reading database requires device ID. */
|
||||
r = sd_device_get_is_initialized(d);
|
||||
if (r > 0) {
|
||||
r = sd_device_get_usec_since_initialized(d, &usec);
|
||||
assert_se((r >= 0 && usec > 0) || r == -ENODATA);
|
||||
} else
|
||||
assert(r == 0);
|
||||
|
||||
r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
|
||||
assert_se(r >= 0 || r == -ENOENT);
|
||||
} else
|
||||
assert_se(r == -ENOENT);
|
||||
|
||||
@ -101,22 +154,6 @@ static void test_sd_device_one(sd_device *d) {
|
||||
} else
|
||||
assert_se(r == -ENOENT);
|
||||
|
||||
r = sd_device_get_ifindex(d, &i);
|
||||
if (r >= 0) {
|
||||
assert_se(i > 0);
|
||||
|
||||
assert_se(sd_device_new_from_ifindex(&dev, i) >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
|
||||
assert_se(sd_device_new_from_ifname(&dev, sysname) >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
dev = sd_device_unref(dev);
|
||||
} else
|
||||
assert_se(r == -ENOENT);
|
||||
|
||||
assert_se(sd_device_get_devpath(d, &val) >= 0);
|
||||
|
||||
r = sd_device_get_devtype(d, &val);
|
||||
@ -128,25 +165,8 @@ static void test_sd_device_one(sd_device *d) {
|
||||
r = sd_device_get_sysnum(d, &val);
|
||||
assert_se(r >= 0 || r == -ENOENT);
|
||||
|
||||
r = sd_device_get_is_initialized(d);
|
||||
if (r > 0) {
|
||||
r = sd_device_get_usec_since_initialized(d, &usec);
|
||||
assert_se((r >= 0 && usec > 0) || r == -ENODATA);
|
||||
} else
|
||||
assert(r == 0);
|
||||
|
||||
r = sd_device_get_sysattr_value(d, "name_assign_type", &val);
|
||||
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL));
|
||||
|
||||
r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
|
||||
assert_se(r >= 0 || r == -ENOENT);
|
||||
|
||||
assert_se(device_get_device_id(d, &id) >= 0);
|
||||
assert_se(sd_device_new_from_device_id(&dev, id) >= 0);
|
||||
assert_se(sd_device_get_syspath(dev, &val) >= 0);
|
||||
assert_se(streq(syspath, val));
|
||||
|
||||
log_info("syspath:%s subsystem:%s id:%s initialized:%s", syspath, strna(subsystem), id, yes_no(i));
|
||||
}
|
||||
|
||||
TEST(sd_device_enumerator_devices) {
|
||||
@ -169,39 +189,54 @@ TEST(sd_device_enumerator_subsystems) {
|
||||
test_sd_device_one(d);
|
||||
}
|
||||
|
||||
static unsigned test_sd_device_enumerator_filter_subsystem_one(const char *subsystem, Hashmap *h) {
|
||||
static void test_sd_device_enumerator_filter_subsystem_one(
|
||||
const char *subsystem,
|
||||
Hashmap *h,
|
||||
unsigned *ret_n_new_dev,
|
||||
unsigned *ret_n_removed_dev) {
|
||||
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
sd_device *d, *t;
|
||||
unsigned n_new_dev = 0;
|
||||
unsigned n_new_dev = 0, n_removed_dev = 0;
|
||||
sd_device *d;
|
||||
|
||||
assert_se(sd_device_enumerator_new(&e) >= 0);
|
||||
assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, true) >= 0);
|
||||
|
||||
FOREACH_DEVICE(e, d) {
|
||||
const char *syspath;
|
||||
sd_device *t;
|
||||
|
||||
assert_se(sd_device_get_syspath(d, &syspath) >= 0);
|
||||
t = hashmap_remove(h, syspath);
|
||||
assert_se(!sd_device_unref(t));
|
||||
|
||||
if (t)
|
||||
log_debug("Removed subsystem:%s syspath:%s", subsystem, syspath);
|
||||
else {
|
||||
if (!t) {
|
||||
log_warning("New device found: subsystem:%s syspath:%s", subsystem, syspath);
|
||||
n_new_dev++;
|
||||
}
|
||||
|
||||
assert_se(!sd_device_unref(t));
|
||||
}
|
||||
|
||||
/* Assume no device is unplugged. */
|
||||
assert_se(hashmap_isempty(h));
|
||||
HASHMAP_FOREACH(d, h) {
|
||||
const char *syspath;
|
||||
|
||||
return n_new_dev;
|
||||
assert_se(sd_device_get_syspath(d, &syspath) >= 0);
|
||||
log_warning("Device removed: subsystem:%s syspath:%s", subsystem, syspath);
|
||||
n_removed_dev++;
|
||||
|
||||
assert_se(!sd_device_unref(d));
|
||||
}
|
||||
|
||||
hashmap_free(h);
|
||||
|
||||
*ret_n_new_dev = n_new_dev;
|
||||
*ret_n_removed_dev = n_removed_dev;
|
||||
}
|
||||
|
||||
TEST(sd_device_enumerator_filter_subsystem) {
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
_cleanup_(hashmap_freep) Hashmap *subsystems;
|
||||
unsigned n_new_dev = 0;
|
||||
unsigned n_new_dev = 0, n_removed_dev = 0;
|
||||
sd_device *d;
|
||||
Hashmap *h;
|
||||
char *s;
|
||||
@ -235,16 +270,22 @@ TEST(sd_device_enumerator_filter_subsystem) {
|
||||
}
|
||||
|
||||
while ((h = hashmap_steal_first_key_and_value(subsystems, (void**) &s))) {
|
||||
n_new_dev += test_sd_device_enumerator_filter_subsystem_one(s, h);
|
||||
hashmap_free(h);
|
||||
unsigned n, m;
|
||||
|
||||
test_sd_device_enumerator_filter_subsystem_one(s, TAKE_PTR(h), &n, &m);
|
||||
free(s);
|
||||
|
||||
n_new_dev += n;
|
||||
n_removed_dev += m;
|
||||
}
|
||||
|
||||
if (n_new_dev > 0)
|
||||
log_warning("%u new device is found in re-scan", n_new_dev);
|
||||
log_warning("%u new devices are found in re-scan", n_new_dev);
|
||||
if (n_removed_dev > 0)
|
||||
log_warning("%u devices removed in re-scan", n_removed_dev);
|
||||
|
||||
/* Assume that not so many devices are plugged. */
|
||||
assert_se(n_new_dev <= 10);
|
||||
/* Assume that not so many devices are plugged or unplugged. */
|
||||
assert_se(n_new_dev + n_removed_dev <= 10);
|
||||
}
|
||||
|
||||
TEST(sd_device_new_from_nulstr) {
|
||||
|
||||
@ -749,10 +749,8 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
assert(filename);
|
||||
|
||||
r = null_or_empty_path(filename);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
|
||||
if (r > 0) {
|
||||
log_debug("Skipping empty file: %s", filename);
|
||||
return 0;
|
||||
@ -777,7 +775,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
netdev_raw,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* config_parse_many() logs internally. */
|
||||
|
||||
/* skip out early if configuration does not match the environment */
|
||||
if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL)) {
|
||||
@ -785,15 +783,11 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (netdev_raw->kind == _NETDEV_KIND_INVALID) {
|
||||
log_warning("NetDev has no Kind= configured in %s. Ignoring", filename);
|
||||
return 0;
|
||||
}
|
||||
if (netdev_raw->kind == _NETDEV_KIND_INVALID)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev has no Kind= configured in \"%s\", ignoring.", filename);
|
||||
|
||||
if (!netdev_raw->ifname) {
|
||||
log_warning("NetDev without Name= configured in %s. Ignoring", filename);
|
||||
return 0;
|
||||
}
|
||||
if (!netdev_raw->ifname)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev without Name= configured in \"%s\", ignoring.", filename);
|
||||
|
||||
netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
|
||||
if (!netdev)
|
||||
@ -815,13 +809,13 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
CONFIG_PARSE_WARN,
|
||||
netdev, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* config_parse_many() logs internally. */
|
||||
|
||||
/* verify configuration */
|
||||
if (NETDEV_VTABLE(netdev)->config_verify) {
|
||||
r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
return r; /* config_verify() logs internally. */
|
||||
}
|
||||
|
||||
netdev->filename = strdup(filename);
|
||||
@ -837,22 +831,21 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
assert(n);
|
||||
if (!streq(netdev->filename, n->filename))
|
||||
log_netdev_warning_errno(netdev, r,
|
||||
"Device was already configured by file %s, ignoring %s.",
|
||||
"Device was already configured by \"%s\", ignoring %s.",
|
||||
n->filename, netdev->filename);
|
||||
|
||||
/* Clear ifname before netdev_free() is called. Otherwise, the NetDev object 'n' is
|
||||
* removed from the hashmap 'manager->netdevs'. */
|
||||
netdev->ifname = mfree(netdev->ifname);
|
||||
return 0;
|
||||
return -EEXIST;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(r > 0);
|
||||
|
||||
log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
|
||||
log_netdev_debug(netdev, "loaded \"%s\"", netdev_kind_to_string(netdev->kind));
|
||||
|
||||
r = netdev_request_to_create(netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* netdev_request_to_create() logs internally. */
|
||||
|
||||
TAKE_PTR(netdev);
|
||||
return 0;
|
||||
@ -871,11 +864,8 @@ int netdev_load(Manager *manager, bool reload) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate netdev files: %m");
|
||||
|
||||
STRV_FOREACH(f, files) {
|
||||
r = netdev_load_one(manager, *f);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
|
||||
}
|
||||
STRV_FOREACH(f, files)
|
||||
(void) netdev_load_one(manager, *f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -313,7 +313,7 @@ int network_verify(Network *network) {
|
||||
|
||||
r = network_drop_invalid_addresses(network);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* network_drop_invalid_addresses() logs internally. */
|
||||
network_drop_invalid_routes(network);
|
||||
network_drop_invalid_nexthops(network);
|
||||
network_drop_invalid_bridge_fdb_entries(network);
|
||||
@ -327,7 +327,7 @@ int network_verify(Network *network) {
|
||||
network_drop_invalid_tclass(network);
|
||||
r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* sr_iov_drop_invalid_sections() logs internally. */
|
||||
network_drop_invalid_static_leases(network);
|
||||
|
||||
network_adjust_dhcp_server(network);
|
||||
@ -346,10 +346,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
assert(filename);
|
||||
|
||||
r = null_or_empty_path(filename);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
|
||||
if (r > 0) {
|
||||
log_debug("Skipping empty file: %s", filename);
|
||||
return 0;
|
||||
@ -365,7 +363,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
|
||||
d = strrchr(name, '.');
|
||||
if (!d)
|
||||
return -EINVAL;
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file name: %s", filename);
|
||||
|
||||
*d = '\0';
|
||||
|
||||
@ -552,7 +550,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
network,
|
||||
&network->stats_by_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* config_parse_many() logs internally. */
|
||||
|
||||
r = network_add_ipv4ll_route(network);
|
||||
if (r < 0)
|
||||
@ -564,15 +562,12 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
network->filename);
|
||||
|
||||
r = network_verify(network);
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
if (r < 0)
|
||||
/* Ignore .network files that do not match the conditions. */
|
||||
return 0;
|
||||
return r; /* network_verify() logs internally. */
|
||||
|
||||
r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
|
||||
|
||||
TAKE_PTR(network);
|
||||
return 0;
|
||||
@ -590,11 +585,8 @@ int network_load(Manager *manager, OrderedHashmap **networks) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate network files: %m");
|
||||
|
||||
STRV_FOREACH(f, files) {
|
||||
r = network_load_one(manager, networks, *f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load %s: %m", *f);
|
||||
}
|
||||
STRV_FOREACH(f, files)
|
||||
(void) network_load_one(manager, networks, *f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ typedef struct BootConfig {
|
||||
|
||||
BootEntry* boot_config_find_entry(BootConfig *config, const char *id);
|
||||
|
||||
static inline BootEntry* boot_config_default_entry(BootConfig *config) {
|
||||
static inline const BootEntry* boot_config_default_entry(const BootConfig *config) {
|
||||
assert(config);
|
||||
|
||||
if (config->default_entry < 0)
|
||||
|
||||
@ -218,10 +218,8 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
|
||||
assert(filename);
|
||||
|
||||
r = null_or_empty_path(filename);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
|
||||
if (r > 0) {
|
||||
log_debug("Skipping empty file: %s", filename);
|
||||
return 0;
|
||||
@ -229,11 +227,11 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
|
||||
|
||||
name = strdup(filename);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
return log_oom();
|
||||
|
||||
config = new(LinkConfig, 1);
|
||||
if (!config)
|
||||
return -ENOMEM;
|
||||
return log_oom();
|
||||
|
||||
*config = (LinkConfig) {
|
||||
.filename = TAKE_PTR(name),
|
||||
@ -266,7 +264,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
|
||||
config_item_perf_lookup, link_config_gperf_lookup,
|
||||
CONFIG_PARSE_WARN, config, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* config_parse_many() logs internally. */
|
||||
|
||||
if (net_match_is_empty(&config->match) && !config->conditions) {
|
||||
log_warning("%s: No valid settings found in the [Match] section, ignoring file. "
|
||||
@ -288,13 +286,13 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
|
||||
|
||||
r = link_adjust_wol_options(config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* link_adjust_wol_options() logs internally. */
|
||||
|
||||
r = sr_iov_drop_invalid_sections(config->sr_iov_num_vfs, config->sr_iov_by_section);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r; /* sr_iov_drop_invalid_sections() logs internally. */
|
||||
|
||||
log_debug("Parsed configuration file %s", filename);
|
||||
log_debug("Parsed configuration file \"%s\"", filename);
|
||||
|
||||
LIST_PREPEND(configs, ctx->configs, TAKE_PTR(config));
|
||||
return 0;
|
||||
@ -340,11 +338,8 @@ int link_config_load(LinkConfigContext *ctx) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "failed to enumerate link files: %m");
|
||||
|
||||
STRV_FOREACH_BACKWARDS(f, files) {
|
||||
r = link_load_one(ctx, *f);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
|
||||
}
|
||||
STRV_FOREACH_BACKWARDS(f, files)
|
||||
(void) link_load_one(ctx, *f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user