diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-07-30 21:36:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-30 21:36:40 +0200 |
commit | c37e0100d834d1f8a5bdf5367f1a74a4ebb9e1be (patch) | |
tree | 8a0a1e8ee46a429e3ffba35fc42d7e05f8f52301 | |
parent | Merge pull request #20172 from poettering/import-util-tweaks (diff) | |
parent | update TODO (diff) | |
download | systemd-c37e0100d834d1f8a5bdf5367f1a74a4ebb9e1be.tar.xz systemd-c37e0100d834d1f8a5bdf5367f1a74a4ebb9e1be.zip |
Merge pull request #20121 from poettering/bootctl-auto
units: run "bootctl update" automatically after boot, to ensure boot loader is regularly updated
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | man/bootctl.xml | 5 | ||||
-rw-r--r-- | presets/90-systemd.preset | 1 | ||||
-rw-r--r-- | src/boot/bootctl.c | 49 | ||||
-rw-r--r-- | units/systemd-boot-update.service | 24 |
5 files changed, 60 insertions, 23 deletions
@@ -1019,10 +1019,6 @@ Features: * bootctl,sd-boot: actually honour the "architecture" key -* sd-boot: add service that automatically runs "bootctl update" on every boot, - in a graceful way, so that updated /usr trees automatically propagate into - updated boot loaders on reboot. - * bootctl: - teach it to prepare an ESP wholesale, i.e. with mkfs.vfat invocation - teach it to copy in unified kernel images and maybe type #1 boot loader spec entries from host diff --git a/man/bootctl.xml b/man/bootctl.xml index d05c3f34d0..a958cde7df 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -233,8 +233,9 @@ <varlistentry> <term><option>--graceful</option></term> - <listitem><para>Ignore failure when the EFI System Partition cannot be found, or when EFI variables - cannot be written. Currently only applies to random seed operations.</para></listitem> + <listitem><para>Ignore failure when the EFI System Partition cannot be found, when EFI variables + cannot be written, or a different or newer boot loader is already installed. Currently only applies + to random seed and update operations.</para></listitem> </varlistentry> <varlistentry> diff --git a/presets/90-systemd.preset b/presets/90-systemd.preset index d26087445c..8a1a08210c 100644 --- a/presets/90-systemd.preset +++ b/presets/90-systemd.preset @@ -22,6 +22,7 @@ enable systemd-resolved.service enable systemd-homed.service enable systemd-userdbd.socket enable systemd-pstore.service +enable systemd-boot-update.service disable console-getty.service disable debug-shell.service diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index fa8c600321..5d126f4bea 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -65,6 +65,7 @@ static const char *arg_dollar_boot_path(void) { static int acquire_esp( bool unprivileged_mode, + bool graceful, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, @@ -80,10 +81,14 @@ static int acquire_esp( * this). */ r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid); - if (r == -ENOKEY) + if (r == -ENOKEY) { + if (graceful) + return log_info_errno(r, "Couldn't find EFI system partition, skipping."); + return log_error_errno(r, "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n" "Alternatively, use --esp-path= to specify path to mount point."); + } if (r < 0) return r; @@ -500,7 +505,7 @@ static int version_check(int fd_from, const char *from, int fd_to, const char *t if (r < 0) return r; if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE), "Source file \"%s\" does not carry version information!", from); @@ -508,12 +513,15 @@ static int version_check(int fd_from, const char *from, int fd_to, const char *t if (r < 0) return r; if (r == 0 || compare_product(a, b) != 0) - return log_notice_errno(SYNTHETIC_ERRNO(EEXIST), + return log_notice_errno(SYNTHETIC_ERRNO(EREMOTE), "Skipping \"%s\", since it's owned by another boot loader.", to); - if (compare_version(a, b) < 0) - return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since a newer boot loader version exists already.", to); + r = compare_version(a, b); + if (r < 0) + return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since newer boot loader version in place already.", to); + else if (r == 0) + return log_info_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since same boot loader version in place already.", to); return 0; } @@ -665,6 +673,10 @@ static int install_binaries(const char *esp_path, bool force) { continue; k = copy_one_file(esp_path, de->d_name, force); + /* Don't propagate an error code if no update necessary, installed version already equal or + * newer version, or other boot loader in place. */ + if (arg_graceful && IN_SET(k, -ESTALE, -EREMOTE)) + continue; if (k < 0 && r == 0) r = k; } @@ -1243,7 +1255,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL; int r, k; - r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &esp_uuid); + r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, &esp_uuid); if (arg_print_esp_path) { if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only * error the find_esp_and_warn() won't log on its own) */ @@ -1254,7 +1266,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { puts(arg_esp_path); } - r = acquire_xbootldr(geteuid() != 0, &xbootldr_uuid); + r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid); if (arg_print_dollar_boot_path) { if (r == -EACCES) return log_error_errno(r, "Failed to determine XBOOTLDR location: %m"); @@ -1402,13 +1414,13 @@ static int verb_list(int argc, char *argv[], void *userdata) { * 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(geteuid() != 0, NULL, NULL, NULL, NULL); + r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL); 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"); if (r < 0) return r; - r = acquire_xbootldr(geteuid() != 0, NULL); + r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL); if (r == -EACCES) return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m"); if (r < 0) @@ -1600,21 +1612,24 @@ static int verb_install(int argc, char *argv[], void *userdata) { sd_id128_t uuid = SD_ID128_NULL; uint64_t pstart = 0, psize = 0; uint32_t part = 0; - bool install; + bool install, graceful; int r; - r = acquire_esp(false, &part, &pstart, &psize, &uuid); + install = streq(argv[0], "install"); + graceful = !install && arg_graceful; /* support graceful mode for updates */ + + r = acquire_esp(/* unprivileged_mode= */ false, graceful, &part, &pstart, &psize, &uuid); + if (graceful && r == -ENOKEY) + return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */ if (r < 0) return r; - r = acquire_xbootldr(false, NULL); + r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL); if (r < 0) return r; settle_make_machine_id_directory(); - install = streq(argv[0], "install"); - RUN_WITH_UMASK(0002) { if (install) { /* Don't create any of these directories when we are just updating. When we update @@ -1663,11 +1678,11 @@ static int verb_remove(int argc, char *argv[], void *userdata) { sd_id128_t uuid = SD_ID128_NULL; int r, q; - r = acquire_esp(false, NULL, NULL, NULL, &uuid); + r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, &uuid); if (r < 0) return r; - r = acquire_xbootldr(false, NULL); + r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL); if (r < 0) return r; @@ -1726,7 +1741,7 @@ static int verb_is_installed(int argc, char *argv[], void *userdata) { _cleanup_free_ char *p = NULL; int r; - r = acquire_esp(false, NULL, NULL, NULL, NULL); + r = acquire_esp(/* privileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, NULL); if (r < 0) return r; diff --git a/units/systemd-boot-update.service b/units/systemd-boot-update.service new file mode 100644 index 0000000000..61ff12762a --- /dev/null +++ b/units/systemd-boot-update.service @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Automatic Boot Loader Update +Documentation=man:bootctl(1) +DefaultDependencies=no +Conflicts=shutdown.target +After=local-fs.target +Before=sysinit.target shutdown.target systemd-update-done.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=bootctl --no-variables --graceful update + +[Install] +WantedBy=sysinit.target |