LCOV - code coverage report
Current view: top level - boot - bootctl.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 26 922 2.8 %
Date: 2019-08-23 13:36:53 Functions: 6 52 11.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8 1010 0.8 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <blkid.h>
       4                 :            : #include <ctype.h>
       5                 :            : #include <dirent.h>
       6                 :            : #include <errno.h>
       7                 :            : #include <ftw.h>
       8                 :            : #include <getopt.h>
       9                 :            : #include <limits.h>
      10                 :            : #include <linux/magic.h>
      11                 :            : #include <stdbool.h>
      12                 :            : #include <stdio.h>
      13                 :            : #include <stdlib.h>
      14                 :            : #include <string.h>
      15                 :            : #include <sys/mman.h>
      16                 :            : #include <sys/stat.h>
      17                 :            : #include <sys/statfs.h>
      18                 :            : #include <unistd.h>
      19                 :            : 
      20                 :            : #include "sd-id128.h"
      21                 :            : 
      22                 :            : #include "alloc-util.h"
      23                 :            : #include "blkid-util.h"
      24                 :            : #include "bootspec.h"
      25                 :            : #include "copy.h"
      26                 :            : #include "dirent-util.h"
      27                 :            : #include "efivars.h"
      28                 :            : #include "env-util.h"
      29                 :            : #include "escape.h"
      30                 :            : #include "fd-util.h"
      31                 :            : #include "fileio.h"
      32                 :            : #include "fs-util.h"
      33                 :            : #include "locale-util.h"
      34                 :            : #include "main-func.h"
      35                 :            : #include "pager.h"
      36                 :            : #include "parse-util.h"
      37                 :            : #include "pretty-print.h"
      38                 :            : #include "random-util.h"
      39                 :            : #include "rm-rf.h"
      40                 :            : #include "stat-util.h"
      41                 :            : #include "stdio-util.h"
      42                 :            : #include "string-util.h"
      43                 :            : #include "strv.h"
      44                 :            : #include "terminal-util.h"
      45                 :            : #include "tmpfile-util.h"
      46                 :            : #include "umask-util.h"
      47                 :            : #include "utf8.h"
      48                 :            : #include "util.h"
      49                 :            : #include "verbs.h"
      50                 :            : #include "virt.h"
      51                 :            : 
      52                 :            : static char *arg_esp_path = NULL;
      53                 :            : static char *arg_xbootldr_path = NULL;
      54                 :            : static bool arg_print_esp_path = false;
      55                 :            : static bool arg_print_dollar_boot_path = false;
      56                 :            : static bool arg_touch_variables = true;
      57                 :            : static PagerFlags arg_pager_flags = 0;
      58                 :            : 
      59                 :         16 : STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
      60                 :         16 : STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
      61                 :            : 
      62                 :          0 : static const char *arg_dollar_boot_path(void) {
      63                 :            :         /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
      64         [ #  # ]:          0 :         return arg_xbootldr_path ?: arg_esp_path;
      65                 :            : }
      66                 :            : 
      67                 :          0 : static int acquire_esp(
      68                 :            :                 bool unprivileged_mode,
      69                 :            :                 uint32_t *ret_part,
      70                 :            :                 uint64_t *ret_pstart,
      71                 :            :                 uint64_t *ret_psize,
      72                 :            :                 sd_id128_t *ret_uuid) {
      73                 :            : 
      74                 :            :         char *np;
      75                 :            :         int r;
      76                 :            : 
      77                 :            :         /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on
      78                 :            :          * its own, except for ENOKEY (which is good, we want to show our own message in that case,
      79                 :            :          * suggesting use of --esp-path=) and EACCESS (only when we request unprivileged mode; in this case
      80                 :            :          * we simply eat up the error here, so that --list and --status work too, without noise about
      81                 :            :          * this). */
      82                 :            : 
      83                 :          0 :         r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
      84         [ #  # ]:          0 :         if (r == -ENOKEY)
      85         [ #  # ]:          0 :                 return log_error_errno(r,
      86                 :            :                                        "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
      87                 :            :                                        "Alternatively, use --esp-path= to specify path to mount point.");
      88         [ #  # ]:          0 :         if (r < 0)
      89                 :          0 :                 return r;
      90                 :            : 
      91                 :          0 :         free_and_replace(arg_esp_path, np);
      92         [ #  # ]:          0 :         log_debug("Using EFI System Partition at %s.", arg_esp_path);
      93                 :            : 
      94                 :          0 :         return 1;
      95                 :            : }
      96                 :            : 
      97                 :          0 : static int acquire_xbootldr(bool unprivileged_mode, sd_id128_t *ret_uuid) {
      98                 :            :         char *np;
      99                 :            :         int r;
     100                 :            : 
     101                 :          0 :         r = find_xbootldr_and_warn(arg_xbootldr_path, unprivileged_mode, &np, ret_uuid);
     102         [ #  # ]:          0 :         if (r == -ENOKEY) {
     103         [ #  # ]:          0 :                 log_debug_errno(r, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
     104         [ #  # ]:          0 :                 if (ret_uuid)
     105                 :          0 :                         *ret_uuid = SD_ID128_NULL;
     106                 :          0 :                 arg_xbootldr_path = mfree(arg_xbootldr_path);
     107                 :          0 :                 return 0;
     108                 :            :         }
     109         [ #  # ]:          0 :         if (r < 0)
     110                 :          0 :                 return r;
     111                 :            : 
     112                 :          0 :         free_and_replace(arg_xbootldr_path, np);
     113         [ #  # ]:          0 :         log_debug("Using XBOOTLDR partition at %s as $BOOT.", arg_xbootldr_path);
     114                 :            : 
     115                 :          0 :         return 1;
     116                 :            : }
     117                 :            : 
     118                 :            : /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
     119                 :          0 : static int get_file_version(int fd, char **v) {
     120                 :            :         struct stat st;
     121                 :            :         char *buf;
     122                 :            :         const char *s, *e;
     123                 :          0 :         char *x = NULL;
     124                 :          0 :         int r = 0;
     125                 :            : 
     126         [ #  # ]:          0 :         assert(fd >= 0);
     127         [ #  # ]:          0 :         assert(v);
     128                 :            : 
     129         [ #  # ]:          0 :         if (fstat(fd, &st) < 0)
     130         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to stat EFI binary: %m");
     131                 :            : 
     132                 :          0 :         r = stat_verify_regular(&st);
     133         [ #  # ]:          0 :         if (r < 0)
     134         [ #  # ]:          0 :                 return log_error_errno(r, "EFI binary is not a regular file: %m");
     135                 :            : 
     136         [ #  # ]:          0 :         if (st.st_size < 27) {
     137                 :          0 :                 *v = NULL;
     138                 :          0 :                 return 0;
     139                 :            :         }
     140                 :            : 
     141                 :          0 :         buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
     142         [ #  # ]:          0 :         if (buf == MAP_FAILED)
     143         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to memory map EFI binary: %m");
     144                 :            : 
     145                 :          0 :         s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
     146         [ #  # ]:          0 :         if (!s)
     147                 :          0 :                 goto finish;
     148                 :          0 :         s += 17;
     149                 :            : 
     150                 :          0 :         e = memmem(s, st.st_size - (s - buf), " ####", 5);
     151   [ #  #  #  # ]:          0 :         if (!e || e - s < 3) {
     152         [ #  # ]:          0 :                 r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
     153                 :          0 :                 goto finish;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         x = strndup(s, e - s);
     157         [ #  # ]:          0 :         if (!x) {
     158                 :          0 :                 r = log_oom();
     159                 :          0 :                 goto finish;
     160                 :            :         }
     161                 :          0 :         r = 1;
     162                 :            : 
     163                 :          0 : finish:
     164                 :          0 :         (void) munmap(buf, st.st_size);
     165                 :          0 :         *v = x;
     166                 :          0 :         return r;
     167                 :            : }
     168                 :            : 
     169                 :          0 : static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
     170                 :          0 :         _cleanup_closedir_ DIR *d = NULL;
     171                 :            :         struct dirent *de;
     172                 :            :         const char *p;
     173                 :          0 :         int c = 0, r;
     174                 :            : 
     175         [ #  # ]:          0 :         assert(esp_path);
     176         [ #  # ]:          0 :         assert(path);
     177                 :            : 
     178   [ #  #  #  #  :          0 :         p = prefix_roota(esp_path, path);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     179                 :          0 :         d = opendir(p);
     180         [ #  # ]:          0 :         if (!d) {
     181         [ #  # ]:          0 :                 if (errno == ENOENT)
     182                 :          0 :                         return 0;
     183                 :            : 
     184         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to read \"%s\": %m", p);
     185                 :            :         }
     186                 :            : 
     187   [ #  #  #  #  :          0 :         FOREACH_DIRENT(de, d, break) {
                   #  # ]
     188      [ #  #  # ]:          0 :                 _cleanup_free_ char *v = NULL;
     189      [ #  #  # ]:          0 :                 _cleanup_close_ int fd = -1;
     190                 :            : 
     191         [ #  # ]:          0 :                 if (!endswith_no_case(de->d_name, ".efi"))
     192                 :          0 :                         continue;
     193                 :            : 
     194   [ #  #  #  # ]:          0 :                 if (prefix && !startswith_no_case(de->d_name, prefix))
     195                 :          0 :                         continue;
     196                 :            : 
     197                 :          0 :                 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
     198         [ #  # ]:          0 :                 if (fd < 0)
     199         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
     200                 :            : 
     201                 :          0 :                 r = get_file_version(fd, &v);
     202         [ #  # ]:          0 :                 if (r < 0)
     203                 :          0 :                         return r;
     204         [ #  # ]:          0 :                 if (r > 0)
     205                 :          0 :                         printf("         File: %s/%s/%s (%s%s%s)\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name, ansi_highlight(), v, ansi_normal());
     206                 :            :                 else
     207                 :          0 :                         printf("         File: %s/%s/%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name);
     208                 :            : 
     209                 :          0 :                 c++;
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         return c;
     213                 :            : }
     214                 :            : 
     215                 :          0 : static int status_binaries(const char *esp_path, sd_id128_t partition) {
     216                 :            :         int r;
     217                 :            : 
     218                 :          0 :         printf("Available Boot Loaders on ESP:\n");
     219                 :            : 
     220         [ #  # ]:          0 :         if (!esp_path) {
     221                 :          0 :                 printf("          ESP: Cannot find or access mount point of ESP.\n\n");
     222                 :          0 :                 return -ENOENT;
     223                 :            :         }
     224                 :            : 
     225                 :          0 :         printf("          ESP: %s", esp_path);
     226         [ #  # ]:          0 :         if (!sd_id128_is_null(partition))
     227                 :          0 :                 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
     228                 :          0 :         printf("\n");
     229                 :            : 
     230                 :          0 :         r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
     231         [ #  # ]:          0 :         if (r < 0)
     232                 :          0 :                 goto finish;
     233         [ #  # ]:          0 :         if (r == 0)
     234         [ #  # ]:          0 :                 log_info("systemd-boot not installed in ESP.");
     235                 :            : 
     236                 :          0 :         r = enumerate_binaries(esp_path, "EFI/BOOT", "boot");
     237         [ #  # ]:          0 :         if (r < 0)
     238                 :          0 :                 goto finish;
     239         [ #  # ]:          0 :         if (r == 0)
     240         [ #  # ]:          0 :                 log_info("No default/fallback boot loader installed in ESP.");
     241                 :            : 
     242                 :          0 :         r = 0;
     243                 :            : 
     244                 :          0 : finish:
     245                 :          0 :         printf("\n");
     246                 :          0 :         return r;
     247                 :            : }
     248                 :            : 
     249                 :          0 : static int print_efi_option(uint16_t id, bool in_order) {
     250                 :          0 :         _cleanup_free_ char *title = NULL;
     251                 :          0 :         _cleanup_free_ char *path = NULL;
     252                 :            :         sd_id128_t partition;
     253                 :            :         bool active;
     254                 :          0 :         int r = 0;
     255                 :            : 
     256                 :          0 :         r = efi_get_boot_option(id, &title, &partition, &path, &active);
     257         [ #  # ]:          0 :         if (r < 0)
     258                 :          0 :                 return r;
     259                 :            : 
     260                 :            :         /* print only configured entries with partition information */
     261   [ #  #  #  # ]:          0 :         if (!path || sd_id128_is_null(partition))
     262                 :          0 :                 return 0;
     263                 :            : 
     264                 :          0 :         efi_tilt_backslashes(path);
     265                 :            : 
     266                 :          0 :         printf("        Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
     267                 :          0 :         printf("           ID: 0x%04X\n", id);
     268   [ #  #  #  # ]:          0 :         printf("       Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
     269                 :          0 :         printf("    Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
     270                 :          0 :                SD_ID128_FORMAT_VAL(partition));
     271                 :          0 :         printf("         File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path);
     272                 :          0 :         printf("\n");
     273                 :            : 
     274                 :          0 :         return 0;
     275                 :            : }
     276                 :            : 
     277                 :          0 : static int status_variables(void) {
     278                 :          0 :         _cleanup_free_ uint16_t *options = NULL, *order = NULL;
     279                 :            :         int n_options, n_order, i;
     280                 :            : 
     281                 :          0 :         n_options = efi_get_boot_options(&options);
     282         [ #  # ]:          0 :         if (n_options == -ENOENT)
     283         [ #  # ]:          0 :                 return log_error_errno(n_options,
     284                 :            :                                        "Failed to access EFI variables, efivarfs"
     285                 :            :                                        " needs to be available at /sys/firmware/efi/efivars/.");
     286         [ #  # ]:          0 :         if (n_options < 0)
     287         [ #  # ]:          0 :                 return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
     288                 :            : 
     289                 :          0 :         n_order = efi_get_boot_order(&order);
     290         [ #  # ]:          0 :         if (n_order == -ENOENT)
     291                 :          0 :                 n_order = 0;
     292         [ #  # ]:          0 :         else if (n_order < 0)
     293         [ #  # ]:          0 :                 return log_error_errno(n_order, "Failed to read EFI boot order: %m");
     294                 :            : 
     295                 :            :         /* print entries in BootOrder first */
     296                 :          0 :         printf("Boot Loaders Listed in EFI Variables:\n");
     297         [ #  # ]:          0 :         for (i = 0; i < n_order; i++)
     298                 :          0 :                 print_efi_option(order[i], true);
     299                 :            : 
     300                 :            :         /* print remaining entries */
     301         [ #  # ]:          0 :         for (i = 0; i < n_options; i++) {
     302                 :            :                 int j;
     303                 :            : 
     304         [ #  # ]:          0 :                 for (j = 0; j < n_order; j++)
     305         [ #  # ]:          0 :                         if (options[i] == order[j])
     306                 :          0 :                                 goto next_option;
     307                 :            : 
     308                 :          0 :                 print_efi_option(options[i], false);
     309                 :            : 
     310                 :          0 :         next_option:
     311                 :          0 :                 continue;
     312                 :            :         }
     313                 :            : 
     314                 :          0 :         return 0;
     315                 :            : }
     316                 :            : 
     317                 :          0 : static int boot_entry_file_check(const char *root, const char *p) {
     318                 :          0 :         _cleanup_free_ char *path;
     319                 :            : 
     320                 :          0 :         path = path_join(root, p);
     321         [ #  # ]:          0 :         if (!path)
     322                 :          0 :                 return log_oom();
     323                 :            : 
     324         [ #  # ]:          0 :         if (access(path, F_OK) < 0)
     325                 :          0 :                 return -errno;
     326                 :            : 
     327                 :          0 :         return 0;
     328                 :            : }
     329                 :            : 
     330                 :          0 : static void boot_entry_file_list(const char *field, const char *root, const char *p, int *ret_status) {
     331                 :          0 :         int status = boot_entry_file_check(root, p);
     332                 :            : 
     333         [ #  # ]:          0 :         printf("%13s%s ", strempty(field), field ? ":" : " ");
     334         [ #  # ]:          0 :         if (status < 0) {
     335                 :          0 :                 errno = -status;
     336                 :          0 :                 printf("%s%s%s (%m)\n", ansi_highlight_red(), p, ansi_normal());
     337                 :            :         } else
     338                 :          0 :                 printf("%s\n", p);
     339                 :            : 
     340   [ #  #  #  # ]:          0 :         if (*ret_status == 0 && status < 0)
     341                 :          0 :                 *ret_status = status;
     342                 :          0 : }
     343                 :            : 
     344                 :          0 : static int boot_entry_show(const BootEntry *e, bool show_as_default) {
     345                 :          0 :         int status = 0;
     346                 :            : 
     347                 :            :         /* Returns 0 on success, negative on processing error, and positive if something is wrong with the
     348                 :            :            boot entry itself. */
     349                 :            : 
     350         [ #  # ]:          0 :         assert(e);
     351                 :            : 
     352         [ #  # ]:          0 :         printf("        title: %s%s%s" "%s%s%s\n",
     353                 :            :                ansi_highlight(), boot_entry_title(e), ansi_normal(),
     354                 :            :                ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal());
     355                 :            : 
     356         [ #  # ]:          0 :         if (e->id)
     357                 :          0 :                 printf("           id: %s\n", e->id);
     358         [ #  # ]:          0 :         if (e->path) {
     359                 :          0 :                 _cleanup_free_ char *link = NULL;
     360                 :            : 
     361                 :            :                 /* Let's urlify the link to make it easy to view in an editor, but only if it is a text
     362                 :            :                  * file. Unified images are binary ELFs, and EFI variables are not pure text either. */
     363         [ #  # ]:          0 :                 if (e->type == BOOT_ENTRY_CONF)
     364                 :          0 :                         (void) terminal_urlify_path(e->path, NULL, &link);
     365                 :            : 
     366         [ #  # ]:          0 :                 printf("       source: %s\n", link ?: e->path);
     367                 :            :         }
     368         [ #  # ]:          0 :         if (e->version)
     369                 :          0 :                 printf("      version: %s\n", e->version);
     370         [ #  # ]:          0 :         if (e->machine_id)
     371                 :          0 :                 printf("   machine-id: %s\n", e->machine_id);
     372         [ #  # ]:          0 :         if (e->architecture)
     373                 :          0 :                 printf(" architecture: %s\n", e->architecture);
     374         [ #  # ]:          0 :         if (e->kernel)
     375                 :          0 :                 boot_entry_file_list("linux", e->root, e->kernel, &status);
     376                 :            : 
     377                 :            :         char **s;
     378   [ #  #  #  # ]:          0 :         STRV_FOREACH(s, e->initrd)
     379                 :          0 :                 boot_entry_file_list(s == e->initrd ? "initrd" : NULL,
     380         [ #  # ]:          0 :                                      e->root,
     381                 :            :                                      *s,
     382                 :            :                                      &status);
     383         [ #  # ]:          0 :         if (!strv_isempty(e->options)) {
     384   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *t = NULL, *t2 = NULL;
     385         [ #  # ]:          0 :                 _cleanup_strv_free_ char **ts = NULL;
     386                 :            : 
     387                 :          0 :                 t = strv_join(e->options, " ");
     388         [ #  # ]:          0 :                 if (!t)
     389                 :          0 :                         return log_oom();
     390                 :            : 
     391                 :          0 :                 ts = strv_split_newlines(t);
     392         [ #  # ]:          0 :                 if (!ts)
     393                 :          0 :                         return log_oom();
     394                 :            : 
     395                 :          0 :                 t2 = strv_join(ts, "\n              ");
     396         [ #  # ]:          0 :                 if (!t2)
     397                 :          0 :                         return log_oom();
     398                 :            : 
     399                 :          0 :                 printf("      options: %s\n", t2);
     400                 :            :         }
     401         [ #  # ]:          0 :         if (e->device_tree)
     402                 :          0 :                 boot_entry_file_list("devicetree", e->root, e->device_tree, &status);
     403                 :            : 
     404                 :          0 :         return -status;
     405                 :            : }
     406                 :            : 
     407                 :          0 : static int status_entries(
     408                 :            :                 const char *esp_path,
     409                 :            :                 sd_id128_t esp_partition_uuid,
     410                 :            :                 const char *xbootldr_path,
     411                 :            :                 sd_id128_t xbootldr_partition_uuid) {
     412                 :            : 
     413                 :          0 :         _cleanup_(boot_config_free) BootConfig config = {};
     414                 :            :         sd_id128_t dollar_boot_partition_uuid;
     415                 :            :         const char *dollar_boot_path;
     416                 :            :         int r;
     417                 :            : 
     418   [ #  #  #  # ]:          0 :         assert(esp_path || xbootldr_path);
     419                 :            : 
     420         [ #  # ]:          0 :         if (xbootldr_path) {
     421                 :          0 :                 dollar_boot_path = xbootldr_path;
     422                 :          0 :                 dollar_boot_partition_uuid = xbootldr_partition_uuid;
     423                 :            :         } else {
     424                 :          0 :                 dollar_boot_path = esp_path;
     425                 :          0 :                 dollar_boot_partition_uuid = esp_partition_uuid;
     426                 :            :         }
     427                 :            : 
     428                 :          0 :         printf("Boot Loader Entries:\n"
     429                 :            :                "        $BOOT: %s", dollar_boot_path);
     430         [ #  # ]:          0 :         if (!sd_id128_is_null(dollar_boot_partition_uuid))
     431                 :          0 :                 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")",
     432                 :          0 :                        SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
     433                 :          0 :         printf("\n\n");
     434                 :            : 
     435                 :          0 :         r = boot_entries_load_config(esp_path, xbootldr_path, &config);
     436         [ #  # ]:          0 :         if (r < 0)
     437                 :          0 :                 return r;
     438                 :            : 
     439         [ #  # ]:          0 :         if (config.default_entry < 0)
     440                 :          0 :                 printf("%zu entries, no entry could be determined as default.\n", config.n_entries);
     441                 :            :         else {
     442                 :          0 :                 printf("Default Boot Loader Entry:\n");
     443                 :            : 
     444                 :          0 :                 r = boot_entry_show(config.entries + config.default_entry, false);
     445         [ #  # ]:          0 :                 if (r > 0)
     446                 :            :                         /* < 0 is already logged by the function itself, let's just emit an extra warning if
     447                 :            :                            the default entry is broken */
     448                 :          0 :                         printf("\nWARNING: default boot entry is broken\n");
     449                 :            :         }
     450                 :            : 
     451                 :          0 :         return 0;
     452                 :            : }
     453                 :            : 
     454                 :          0 : static int compare_product(const char *a, const char *b) {
     455                 :            :         size_t x, y;
     456                 :            : 
     457         [ #  # ]:          0 :         assert(a);
     458         [ #  # ]:          0 :         assert(b);
     459                 :            : 
     460                 :          0 :         x = strcspn(a, " ");
     461                 :          0 :         y = strcspn(b, " ");
     462         [ #  # ]:          0 :         if (x != y)
     463         [ #  # ]:          0 :                 return x < y ? -1 : x > y ? 1 : 0;
     464                 :            : 
     465                 :          0 :         return strncmp(a, b, x);
     466                 :            : }
     467                 :            : 
     468                 :          0 : static int compare_version(const char *a, const char *b) {
     469         [ #  # ]:          0 :         assert(a);
     470         [ #  # ]:          0 :         assert(b);
     471                 :            : 
     472                 :          0 :         a += strcspn(a, " ");
     473                 :          0 :         a += strspn(a, " ");
     474                 :          0 :         b += strcspn(b, " ");
     475                 :          0 :         b += strspn(b, " ");
     476                 :            : 
     477                 :          0 :         return strverscmp(a, b);
     478                 :            : }
     479                 :            : 
     480                 :          0 : static int version_check(int fd_from, const char *from, int fd_to, const char *to) {
     481                 :          0 :         _cleanup_free_ char *a = NULL, *b = NULL;
     482                 :            :         int r;
     483                 :            : 
     484         [ #  # ]:          0 :         assert(fd_from >= 0);
     485         [ #  # ]:          0 :         assert(from);
     486         [ #  # ]:          0 :         assert(fd_to >= 0);
     487         [ #  # ]:          0 :         assert(to);
     488                 :            : 
     489                 :          0 :         r = get_file_version(fd_from, &a);
     490         [ #  # ]:          0 :         if (r < 0)
     491                 :          0 :                 return r;
     492         [ #  # ]:          0 :         if (r == 0)
     493         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     494                 :            :                                        "Source file \"%s\" does not carry version information!",
     495                 :            :                                        from);
     496                 :            : 
     497                 :          0 :         r = get_file_version(fd_to, &b);
     498         [ #  # ]:          0 :         if (r < 0)
     499                 :          0 :                 return r;
     500   [ #  #  #  # ]:          0 :         if (r == 0 || compare_product(a, b) != 0)
     501         [ #  # ]:          0 :                 return log_notice_errno(SYNTHETIC_ERRNO(EEXIST),
     502                 :            :                                         "Skipping \"%s\", since it's owned by another boot loader.",
     503                 :            :                                         to);
     504                 :            : 
     505         [ #  # ]:          0 :         if (compare_version(a, b) < 0)
     506         [ #  # ]:          0 :                 return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since a newer boot loader version exists already.", to);
     507                 :            : 
     508                 :          0 :         return 0;
     509                 :            : }
     510                 :            : 
     511                 :          0 : static int copy_file_with_version_check(const char *from, const char *to, bool force) {
     512                 :          0 :         _cleanup_close_ int fd_from = -1, fd_to = -1;
     513                 :          0 :         _cleanup_free_ char *t = NULL;
     514                 :            :         int r;
     515                 :            : 
     516                 :          0 :         fd_from = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
     517         [ #  # ]:          0 :         if (fd_from < 0)
     518         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", from);
     519                 :            : 
     520         [ #  # ]:          0 :         if (!force) {
     521                 :          0 :                 fd_to = open(to, O_RDONLY|O_CLOEXEC|O_NOCTTY);
     522         [ #  # ]:          0 :                 if (fd_to < 0) {
     523         [ #  # ]:          0 :                         if (errno != -ENOENT)
     524         [ #  # ]:          0 :                                 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
     525                 :            :                 } else {
     526                 :          0 :                         r = version_check(fd_from, from, fd_to, to);
     527         [ #  # ]:          0 :                         if (r < 0)
     528                 :          0 :                                 return r;
     529                 :            : 
     530         [ #  # ]:          0 :                         if (lseek(fd_from, 0, SEEK_SET) == (off_t) -1)
     531         [ #  # ]:          0 :                                 return log_error_errno(errno, "Failed to seek in \"%s\": %m", from);
     532                 :            : 
     533                 :          0 :                         fd_to = safe_close(fd_to);
     534                 :            :                 }
     535                 :            :         }
     536                 :            : 
     537                 :          0 :         r = tempfn_random(to, NULL, &t);
     538         [ #  # ]:          0 :         if (r < 0)
     539                 :          0 :                 return log_oom();
     540                 :            : 
     541   [ #  #  #  # ]:          0 :         RUN_WITH_UMASK(0000) {
     542                 :          0 :                 fd_to = open(t, O_WRONLY|O_CREAT|O_CLOEXEC|O_EXCL|O_NOFOLLOW, 0644);
     543         [ #  # ]:          0 :                 if (fd_to < 0)
     544         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", t);
     545                 :            :         }
     546                 :            : 
     547                 :          0 :         r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK);
     548         [ #  # ]:          0 :         if (r < 0) {
     549                 :          0 :                 (void) unlink(t);
     550         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
     551                 :            :         }
     552                 :            : 
     553                 :          0 :         (void) copy_times(fd_from, fd_to, 0);
     554                 :            : 
     555         [ #  # ]:          0 :         if (fsync(fd_to) < 0) {
     556                 :          0 :                 (void) unlink_noerrno(t);
     557         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
     558                 :            :         }
     559                 :            : 
     560                 :          0 :         (void) fsync_directory_of_file(fd_to);
     561                 :            : 
     562         [ #  # ]:          0 :         if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0) {
     563                 :          0 :                 (void) unlink_noerrno(t);
     564         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", t, to);
     565                 :            :         }
     566                 :            : 
     567         [ #  # ]:          0 :         log_info("Copied \"%s\" to \"%s\".", from, to);
     568                 :            : 
     569                 :          0 :         return 0;
     570                 :            : }
     571                 :            : 
     572                 :          0 : static int mkdir_one(const char *prefix, const char *suffix) {
     573                 :          0 :         _cleanup_free_ char *p = NULL;
     574                 :            : 
     575                 :          0 :         p = path_join(prefix, suffix);
     576         [ #  # ]:          0 :         if (mkdir(p, 0700) < 0) {
     577         [ #  # ]:          0 :                 if (errno != EEXIST)
     578         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to create \"%s\": %m", p);
     579                 :            :         } else
     580         [ #  # ]:          0 :                 log_info("Created \"%s\".", p);
     581                 :            : 
     582                 :          0 :         return 0;
     583                 :            : }
     584                 :            : 
     585                 :            : static const char *const esp_subdirs[] = {
     586                 :            :         /* The directories to place in the ESP */
     587                 :            :         "EFI",
     588                 :            :         "EFI/systemd",
     589                 :            :         "EFI/BOOT",
     590                 :            :         "loader",
     591                 :            :         NULL
     592                 :            : };
     593                 :            : 
     594                 :            : static const char *const dollar_boot_subdirs[] = {
     595                 :            :         /* The directories to place in the XBOOTLDR partition or the ESP, depending what exists */
     596                 :            :         "loader",
     597                 :            :         "loader/entries",  /* Type #1 entries */
     598                 :            :         "EFI",
     599                 :            :         "EFI/Linux",       /* Type #2 entries */
     600                 :            :         NULL
     601                 :            : };
     602                 :            : 
     603                 :          0 : static int create_subdirs(const char *root, const char * const *subdirs) {
     604                 :            :         const char *const *i;
     605                 :            :         int r;
     606                 :            : 
     607   [ #  #  #  # ]:          0 :         STRV_FOREACH(i, subdirs) {
     608                 :          0 :                 r = mkdir_one(root, *i);
     609         [ #  # ]:          0 :                 if (r < 0)
     610                 :          0 :                         return r;
     611                 :            :         }
     612                 :            : 
     613                 :          0 :         return 0;
     614                 :            : }
     615                 :            : 
     616                 :          0 : static int copy_one_file(const char *esp_path, const char *name, bool force) {
     617                 :            :         const char *e;
     618                 :            :         char *p, *q;
     619                 :            :         int r;
     620                 :            : 
     621   [ #  #  #  #  :          0 :         p = strjoina(BOOTLIBDIR "/", name);
          #  #  #  #  #  
                #  #  # ]
     622   [ #  #  #  #  :          0 :         q = strjoina(esp_path, "/EFI/systemd/", name);
          #  #  #  #  #  
                #  #  # ]
     623                 :          0 :         r = copy_file_with_version_check(p, q, force);
     624                 :            : 
     625                 :          0 :         e = startswith(name, "systemd-boot");
     626         [ #  # ]:          0 :         if (e) {
     627                 :            :                 int k;
     628                 :            :                 char *v;
     629                 :            : 
     630                 :            :                 /* Create the EFI default boot loader name (specified for removable devices) */
     631   [ #  #  #  #  :          0 :                 v = strjoina(esp_path, "/EFI/BOOT/BOOT", e);
          #  #  #  #  #  
                #  #  # ]
     632                 :          0 :                 ascii_strupper(strrchr(v, '/') + 1);
     633                 :            : 
     634                 :          0 :                 k = copy_file_with_version_check(p, v, force);
     635   [ #  #  #  # ]:          0 :                 if (k < 0 && r == 0)
     636                 :          0 :                         r = k;
     637                 :            :         }
     638                 :            : 
     639                 :          0 :         return r;
     640                 :            : }
     641                 :            : 
     642                 :          0 : static int install_binaries(const char *esp_path, bool force) {
     643                 :            :         struct dirent *de;
     644                 :          0 :         _cleanup_closedir_ DIR *d = NULL;
     645                 :          0 :         int r = 0;
     646                 :            : 
     647                 :          0 :         d = opendir(BOOTLIBDIR);
     648         [ #  # ]:          0 :         if (!d)
     649         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m");
     650                 :            : 
     651   [ #  #  #  #  :          0 :         FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read \""BOOTLIBDIR"\": %m")) {
             #  #  #  # ]
     652                 :            :                 int k;
     653                 :            : 
     654         [ #  # ]:          0 :                 if (!endswith_no_case(de->d_name, ".efi"))
     655                 :          0 :                         continue;
     656                 :            : 
     657                 :          0 :                 k = copy_one_file(esp_path, de->d_name, force);
     658   [ #  #  #  # ]:          0 :                 if (k < 0 && r == 0)
     659                 :          0 :                         r = k;
     660                 :            :         }
     661                 :            : 
     662                 :          0 :         return r;
     663                 :            : }
     664                 :            : 
     665                 :          0 : static bool same_entry(uint16_t id, sd_id128_t uuid, const char *path) {
     666                 :          0 :         _cleanup_free_ char *opath = NULL;
     667                 :            :         sd_id128_t ouuid;
     668                 :            :         int r;
     669                 :            : 
     670                 :          0 :         r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
     671         [ #  # ]:          0 :         if (r < 0)
     672                 :          0 :                 return false;
     673         [ #  # ]:          0 :         if (!sd_id128_equal(uuid, ouuid))
     674                 :          0 :                 return false;
     675         [ #  # ]:          0 :         if (!streq_ptr(path, opath))
     676                 :          0 :                 return false;
     677                 :            : 
     678                 :          0 :         return true;
     679                 :            : }
     680                 :            : 
     681                 :          0 : static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
     682                 :          0 :         _cleanup_free_ uint16_t *options = NULL;
     683                 :            :         int n, i;
     684                 :            : 
     685                 :          0 :         n = efi_get_boot_options(&options);
     686         [ #  # ]:          0 :         if (n < 0)
     687                 :          0 :                 return n;
     688                 :            : 
     689                 :            :         /* find already existing systemd-boot entry */
     690         [ #  # ]:          0 :         for (i = 0; i < n; i++)
     691         [ #  # ]:          0 :                 if (same_entry(options[i], uuid, path)) {
     692                 :          0 :                         *id = options[i];
     693                 :          0 :                         return 1;
     694                 :            :                 }
     695                 :            : 
     696                 :            :         /* find free slot in the sorted BootXXXX variable list */
     697         [ #  # ]:          0 :         for (i = 0; i < n; i++)
     698         [ #  # ]:          0 :                 if (i != options[i]) {
     699                 :          0 :                         *id = i;
     700                 :          0 :                         return 1;
     701                 :            :                 }
     702                 :            : 
     703                 :            :         /* use the next one */
     704         [ #  # ]:          0 :         if (i == 0xffff)
     705                 :          0 :                 return -ENOSPC;
     706                 :          0 :         *id = i;
     707                 :          0 :         return 0;
     708                 :            : }
     709                 :            : 
     710                 :          0 : static int insert_into_order(uint16_t slot, bool first) {
     711                 :          0 :         _cleanup_free_ uint16_t *order = NULL;
     712                 :            :         uint16_t *t;
     713                 :            :         int n, i;
     714                 :            : 
     715                 :          0 :         n = efi_get_boot_order(&order);
     716         [ #  # ]:          0 :         if (n <= 0)
     717                 :            :                 /* no entry, add us */
     718                 :          0 :                 return efi_set_boot_order(&slot, 1);
     719                 :            : 
     720                 :            :         /* are we the first and only one? */
     721   [ #  #  #  # ]:          0 :         if (n == 1 && order[0] == slot)
     722                 :          0 :                 return 0;
     723                 :            : 
     724                 :            :         /* are we already in the boot order? */
     725         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     726         [ #  # ]:          0 :                 if (order[i] != slot)
     727                 :          0 :                         continue;
     728                 :            : 
     729                 :            :                 /* we do not require to be the first one, all is fine */
     730         [ #  # ]:          0 :                 if (!first)
     731                 :          0 :                         return 0;
     732                 :            : 
     733                 :            :                 /* move us to the first slot */
     734                 :          0 :                 memmove(order + 1, order, i * sizeof(uint16_t));
     735                 :          0 :                 order[0] = slot;
     736                 :          0 :                 return efi_set_boot_order(order, n);
     737                 :            :         }
     738                 :            : 
     739                 :            :         /* extend array */
     740                 :          0 :         t = reallocarray(order, n + 1, sizeof(uint16_t));
     741         [ #  # ]:          0 :         if (!t)
     742                 :          0 :                 return -ENOMEM;
     743                 :          0 :         order = t;
     744                 :            : 
     745                 :            :         /* add us to the top or end of the list */
     746         [ #  # ]:          0 :         if (first) {
     747                 :          0 :                 memmove(order + 1, order, n * sizeof(uint16_t));
     748                 :          0 :                 order[0] = slot;
     749                 :            :         } else
     750                 :          0 :                 order[n] = slot;
     751                 :            : 
     752                 :          0 :         return efi_set_boot_order(order, n + 1);
     753                 :            : }
     754                 :            : 
     755                 :          0 : static int remove_from_order(uint16_t slot) {
     756                 :          0 :         _cleanup_free_ uint16_t *order = NULL;
     757                 :            :         int n, i;
     758                 :            : 
     759                 :          0 :         n = efi_get_boot_order(&order);
     760         [ #  # ]:          0 :         if (n <= 0)
     761                 :          0 :                 return n;
     762                 :            : 
     763         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     764         [ #  # ]:          0 :                 if (order[i] != slot)
     765                 :          0 :                         continue;
     766                 :            : 
     767         [ #  # ]:          0 :                 if (i + 1 < n)
     768                 :          0 :                         memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
     769                 :          0 :                 return efi_set_boot_order(order, n - 1);
     770                 :            :         }
     771                 :            : 
     772                 :          0 :         return 0;
     773                 :            : }
     774                 :            : 
     775                 :          0 : static int install_variables(const char *esp_path,
     776                 :            :                              uint32_t part, uint64_t pstart, uint64_t psize,
     777                 :            :                              sd_id128_t uuid, const char *path,
     778                 :            :                              bool first) {
     779                 :            :         const char *p;
     780                 :            :         uint16_t slot;
     781                 :            :         int r;
     782                 :            : 
     783         [ #  # ]:          0 :         if (!is_efi_boot()) {
     784         [ #  # ]:          0 :                 log_warning("Not booted with EFI, skipping EFI variable setup.");
     785                 :          0 :                 return 0;
     786                 :            :         }
     787                 :            : 
     788   [ #  #  #  #  :          0 :         p = prefix_roota(esp_path, path);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     789         [ #  # ]:          0 :         if (access(p, F_OK) < 0) {
     790         [ #  # ]:          0 :                 if (errno == ENOENT)
     791                 :          0 :                         return 0;
     792                 :            : 
     793         [ #  # ]:          0 :                 return log_error_errno(errno, "Cannot access \"%s\": %m", p);
     794                 :            :         }
     795                 :            : 
     796                 :          0 :         r = find_slot(uuid, path, &slot);
     797         [ #  # ]:          0 :         if (r < 0)
     798   [ #  #  #  # ]:          0 :                 return log_error_errno(r,
     799                 :            :                                        r == -ENOENT ?
     800                 :            :                                        "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
     801                 :            :                                        "Failed to determine current boot order: %m");
     802                 :            : 
     803   [ #  #  #  # ]:          0 :         if (first || r == 0) {
     804                 :          0 :                 r = efi_add_boot_option(slot, "Linux Boot Manager",
     805                 :            :                                         part, pstart, psize,
     806                 :            :                                         uuid, path);
     807         [ #  # ]:          0 :                 if (r < 0)
     808         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
     809                 :            : 
     810         [ #  # ]:          0 :                 log_info("Created EFI boot entry \"Linux Boot Manager\".");
     811                 :            :         }
     812                 :            : 
     813                 :          0 :         return insert_into_order(slot, first);
     814                 :            : }
     815                 :            : 
     816                 :          0 : static int remove_boot_efi(const char *esp_path) {
     817                 :          0 :         _cleanup_closedir_ DIR *d = NULL;
     818                 :            :         struct dirent *de;
     819                 :            :         const char *p;
     820                 :          0 :         int r, c = 0;
     821                 :            : 
     822   [ #  #  #  #  :          0 :         p = prefix_roota(esp_path, "/EFI/BOOT");
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     823                 :          0 :         d = opendir(p);
     824         [ #  # ]:          0 :         if (!d) {
     825         [ #  # ]:          0 :                 if (errno == ENOENT)
     826                 :          0 :                         return 0;
     827                 :            : 
     828         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to open directory \"%s\": %m", p);
     829                 :            :         }
     830                 :            : 
     831   [ #  #  #  #  :          0 :         FOREACH_DIRENT(de, d, break) {
                   #  # ]
     832      [ #  #  # ]:          0 :                 _cleanup_close_ int fd = -1;
     833      [ #  #  # ]:          0 :                 _cleanup_free_ char *v = NULL;
     834                 :            : 
     835         [ #  # ]:          0 :                 if (!endswith_no_case(de->d_name, ".efi"))
     836                 :          0 :                         continue;
     837                 :            : 
     838         [ #  # ]:          0 :                 if (!startswith_no_case(de->d_name, "boot"))
     839                 :          0 :                         continue;
     840                 :            : 
     841                 :          0 :                 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
     842         [ #  # ]:          0 :                 if (fd < 0)
     843         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
     844                 :            : 
     845                 :          0 :                 r = get_file_version(fd, &v);
     846         [ #  # ]:          0 :                 if (r < 0)
     847                 :          0 :                         return r;
     848   [ #  #  #  # ]:          0 :                 if (r > 0 && startswith(v, "systemd-boot ")) {
     849                 :          0 :                         r = unlinkat(dirfd(d), de->d_name, 0);
     850         [ #  # ]:          0 :                         if (r < 0)
     851         [ #  # ]:          0 :                                 return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name);
     852                 :            : 
     853         [ #  # ]:          0 :                         log_info("Removed \"%s/%s\".", p, de->d_name);
     854                 :            :                 }
     855                 :            : 
     856                 :          0 :                 c++;
     857                 :            :         }
     858                 :            : 
     859                 :          0 :         return c;
     860                 :            : }
     861                 :            : 
     862                 :          0 : static int rmdir_one(const char *prefix, const char *suffix) {
     863                 :            :         const char *p;
     864                 :            : 
     865   [ #  #  #  #  :          0 :         p = prefix_roota(prefix, suffix);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     866         [ #  # ]:          0 :         if (rmdir(p) < 0) {
     867         [ #  # ]:          0 :                 bool ignore = IN_SET(errno, ENOENT, ENOTEMPTY);
     868                 :            : 
     869   [ #  #  #  # ]:          0 :                 log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, errno,
     870                 :            :                                "Failed to remove directory \"%s\": %m", p);
     871         [ #  # ]:          0 :                 if (!ignore)
     872                 :          0 :                         return -errno;
     873                 :            :         } else
     874         [ #  # ]:          0 :                 log_info("Removed \"%s\".", p);
     875                 :            : 
     876                 :          0 :         return 0;
     877                 :            : }
     878                 :            : 
     879                 :          0 : static int remove_subdirs(const char *root, const char *const *subdirs) {
     880                 :            :         int r, q;
     881                 :            : 
     882                 :            :         /* We use recursion here to destroy the directories in reverse order. Which should be safe given how
     883                 :            :          * short the array is. */
     884                 :            : 
     885         [ #  # ]:          0 :         if (!subdirs[0]) /* A the end of the list */
     886                 :          0 :                 return 0;
     887                 :            : 
     888                 :          0 :         r = remove_subdirs(root, subdirs + 1);
     889                 :          0 :         q = rmdir_one(root, subdirs[0]);
     890                 :            : 
     891         [ #  # ]:          0 :         return r < 0 ? r : q;
     892                 :            : }
     893                 :            : 
     894                 :          0 : static int remove_machine_id_directory(const char *root, sd_id128_t machine_id) {
     895                 :            :         char buf[SD_ID128_STRING_MAX];
     896                 :            : 
     897         [ #  # ]:          0 :         assert(root);
     898                 :            : 
     899                 :          0 :         return rmdir_one(root, sd_id128_to_string(machine_id, buf));
     900                 :            : }
     901                 :            : 
     902                 :          0 : static int remove_binaries(const char *esp_path) {
     903                 :            :         const char *p;
     904                 :            :         int r, q;
     905                 :            : 
     906   [ #  #  #  #  :          0 :         p = prefix_roota(esp_path, "/EFI/systemd");
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     907                 :          0 :         r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
     908                 :            : 
     909                 :          0 :         q = remove_boot_efi(esp_path);
     910   [ #  #  #  # ]:          0 :         if (q < 0 && r == 0)
     911                 :          0 :                 r = q;
     912                 :            : 
     913                 :          0 :         return r;
     914                 :            : }
     915                 :            : 
     916                 :          0 : static int remove_file(const char *root, const char *file) {
     917                 :            :         const char *p;
     918                 :            : 
     919         [ #  # ]:          0 :         assert(root);
     920         [ #  # ]:          0 :         assert(file);
     921                 :            : 
     922   [ #  #  #  #  :          0 :         p = prefix_roota(root, file);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     923         [ #  # ]:          0 :         if (unlink(p) < 0) {
     924   [ #  #  #  # ]:          0 :                 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
     925                 :            :                                "Failed to unlink file \"%s\": %m", p);
     926                 :            : 
     927         [ #  # ]:          0 :                 return errno == ENOENT ? 0 : -errno;
     928                 :            :         }
     929                 :            : 
     930         [ #  # ]:          0 :         log_info("Removed \"%s\".", p);
     931                 :          0 :         return 1;
     932                 :            : }
     933                 :            : 
     934                 :          0 : static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
     935                 :            :         uint16_t slot;
     936                 :            :         int r;
     937                 :            : 
     938         [ #  # ]:          0 :         if (!is_efi_boot())
     939                 :          0 :                 return 0;
     940                 :            : 
     941                 :          0 :         r = find_slot(uuid, path, &slot);
     942         [ #  # ]:          0 :         if (r != 1)
     943                 :          0 :                 return 0;
     944                 :            : 
     945                 :          0 :         r = efi_remove_boot_option(slot);
     946         [ #  # ]:          0 :         if (r < 0)
     947                 :          0 :                 return r;
     948                 :            : 
     949         [ #  # ]:          0 :         if (in_order)
     950                 :          0 :                 return remove_from_order(slot);
     951                 :            : 
     952                 :          0 :         return 0;
     953                 :            : }
     954                 :            : 
     955                 :          0 : static int remove_loader_variables(void) {
     956                 :            :         const char *p;
     957                 :          0 :         int r = 0;
     958                 :            : 
     959                 :            :         /* Remove all persistent loader variables we define */
     960                 :            : 
     961         [ #  # ]:          0 :         FOREACH_STRING(p,
     962                 :            :                        "LoaderConfigTimeout",
     963                 :            :                        "LoaderConfigTimeoutOneShot",
     964                 :            :                        "LoaderEntryDefault",
     965                 :            :                        "LoaderEntryOneShot",
     966                 :            :                        "LoaderSystemToken") {
     967                 :            : 
     968                 :            :                 int q;
     969                 :            : 
     970                 :          0 :                 q = efi_set_variable(EFI_VENDOR_LOADER, p, NULL, 0);
     971         [ #  # ]:          0 :                 if (q == -ENOENT)
     972                 :          0 :                         continue;
     973         [ #  # ]:          0 :                 if (q < 0) {
     974         [ #  # ]:          0 :                         log_warning_errno(q, "Failed to remove %s variable: %m", p);
     975         [ #  # ]:          0 :                         if (r >= 0)
     976                 :          0 :                                 r = q;
     977                 :            :                 } else
     978         [ #  # ]:          0 :                         log_info("Removed EFI variable %s.", p);
     979                 :            :         }
     980                 :            : 
     981                 :          0 :         return r;
     982                 :            : }
     983                 :            : 
     984                 :          0 : static int install_loader_config(const char *esp_path, sd_id128_t machine_id) {
     985                 :            :         char machine_string[SD_ID128_STRING_MAX];
     986                 :          0 :         _cleanup_(unlink_and_freep) char *t = NULL;
     987                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     988                 :            :         const char *p;
     989                 :            :         int r, fd;
     990                 :            : 
     991   [ #  #  #  #  :          0 :         p = prefix_roota(esp_path, "/loader/loader.conf");
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     992         [ #  # ]:          0 :         if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
     993                 :          0 :                 return 0;
     994                 :            : 
     995                 :          0 :         fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
     996         [ #  # ]:          0 :         if (fd < 0)
     997         [ #  # ]:          0 :                 return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p);
     998                 :            : 
     999                 :          0 :         f = fdopen(fd, "w");
    1000         [ #  # ]:          0 :         if (!f) {
    1001                 :          0 :                 safe_close(fd);
    1002                 :          0 :                 return log_oom();
    1003                 :            :         }
    1004                 :            : 
    1005                 :          0 :         fprintf(f, "#timeout 3\n"
    1006                 :            :                    "#console-mode keep\n"
    1007                 :            :                    "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
    1008                 :            : 
    1009                 :          0 :         r = fflush_sync_and_check(f);
    1010         [ #  # ]:          0 :         if (r < 0)
    1011         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to write \"%s\": %m", p);
    1012                 :            : 
    1013                 :          0 :         r = link_tmpfile(fd, t, p);
    1014         [ #  # ]:          0 :         if (r == -EEXIST)
    1015                 :          0 :                 return 0; /* Silently skip creation if the file exists now (recheck) */
    1016         [ #  # ]:          0 :         if (r < 0)
    1017         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
    1018                 :            : 
    1019                 :          0 :         t = mfree(t);
    1020                 :          0 :         return 1;
    1021                 :            : }
    1022                 :            : 
    1023                 :          0 : static int install_machine_id_directory(const char *root, sd_id128_t machine_id) {
    1024                 :            :         char buf[SD_ID128_STRING_MAX];
    1025                 :            : 
    1026         [ #  # ]:          0 :         assert(root);
    1027                 :            : 
    1028                 :          0 :         return mkdir_one(root, sd_id128_to_string(machine_id, buf));
    1029                 :            : }
    1030                 :            : 
    1031                 :         12 : static int help(int argc, char *argv[], void *userdata) {
    1032                 :         12 :         _cleanup_free_ char *link = NULL;
    1033                 :            :         int r;
    1034                 :            : 
    1035                 :         12 :         r = terminal_urlify_man("bootctl", "1", &link);
    1036         [ -  + ]:         12 :         if (r < 0)
    1037                 :          0 :                 return log_oom();
    1038                 :            : 
    1039                 :         12 :         printf("%s [COMMAND] [OPTIONS...]\n\n"
    1040                 :            :                "Install, update or remove the systemd-boot EFI boot manager.\n\n"
    1041                 :            :                "  -h --help            Show this help\n"
    1042                 :            :                "     --version         Print version\n"
    1043                 :            :                "     --esp-path=PATH   Path to the EFI System Partition (ESP)\n"
    1044                 :            :                "     --boot-path=PATH  Path to the $BOOT partition\n"
    1045                 :            :                "  -p --print-esp-path  Print path to the EFI System Partition\n"
    1046                 :            :                "  -x --print-boot-path Print path to the $BOOT partition\n"
    1047                 :            :                "     --no-variables    Don't touch EFI variables\n"
    1048                 :            :                "     --no-pager        Do not pipe output into a pager\n"
    1049                 :            :                "\nBoot Loader Commands:\n"
    1050                 :            :                "     status            Show status of installed systemd-boot and EFI variables\n"
    1051                 :            :                "     install           Install systemd-boot to the ESP and EFI variables\n"
    1052                 :            :                "     update            Update systemd-boot in the ESP and EFI variables\n"
    1053                 :            :                "     remove            Remove systemd-boot from the ESP and EFI variables\n"
    1054                 :            :                "     random-seed       Initialize random seed in ESP and EFI variables\n"
    1055                 :            :                "     is-installed      Test whether systemd-boot is installed in the ESP\n"
    1056                 :            :                "\nBoot Loader Entries Commands:\n"
    1057                 :            :                "     list              List boot loader entries\n"
    1058                 :            :                "     set-default ID    Set default boot loader entry\n"
    1059                 :            :                "     set-oneshot ID    Set default boot loader entry, for next boot only\n"
    1060                 :            :                "\nSee the %s for details.\n"
    1061                 :            :                , program_invocation_short_name
    1062                 :            :                , link);
    1063                 :            : 
    1064                 :         12 :         return 0;
    1065                 :            : }
    1066                 :            : 
    1067                 :         16 : static int parse_argv(int argc, char *argv[]) {
    1068                 :            :         enum {
    1069                 :            :                 ARG_ESP_PATH = 0x100,
    1070                 :            :                 ARG_BOOT_PATH,
    1071                 :            :                 ARG_VERSION,
    1072                 :            :                 ARG_NO_VARIABLES,
    1073                 :            :                 ARG_NO_PAGER,
    1074                 :            :         };
    1075                 :            : 
    1076                 :            :         static const struct option options[] = {
    1077                 :            :                 { "help",            no_argument,       NULL, 'h'                 },
    1078                 :            :                 { "version",         no_argument,       NULL, ARG_VERSION         },
    1079                 :            :                 { "esp-path",        required_argument, NULL, ARG_ESP_PATH        },
    1080                 :            :                 { "path",            required_argument, NULL, ARG_ESP_PATH        }, /* Compatibility alias */
    1081                 :            :                 { "boot-path",       required_argument, NULL, ARG_BOOT_PATH       },
    1082                 :            :                 { "print-esp-path",  no_argument,       NULL, 'p'                 },
    1083                 :            :                 { "print-path",      no_argument,       NULL, 'p'                 }, /* Compatibility alias */
    1084                 :            :                 { "print-boot-path", no_argument,       NULL, 'x'                 },
    1085                 :            :                 { "no-variables",    no_argument,       NULL, ARG_NO_VARIABLES    },
    1086                 :            :                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
    1087                 :            :                 {}
    1088                 :            :         };
    1089                 :            : 
    1090                 :            :         int c, r;
    1091                 :            : 
    1092         [ -  + ]:         16 :         assert(argc >= 0);
    1093         [ -  + ]:         16 :         assert(argv);
    1094                 :            : 
    1095         [ +  - ]:         16 :         while ((c = getopt_long(argc, argv, "hpx", options, NULL)) >= 0)
    1096   [ +  -  -  -  :         16 :                 switch (c) {
          -  -  -  -  +  
                      - ]
    1097                 :            : 
    1098                 :         12 :                 case 'h':
    1099                 :         12 :                         help(0, NULL, NULL);
    1100                 :         12 :                         return 0;
    1101                 :            : 
    1102                 :          0 :                 case ARG_VERSION:
    1103                 :          0 :                         return version();
    1104                 :            : 
    1105                 :          0 :                 case ARG_ESP_PATH:
    1106                 :          0 :                         r = free_and_strdup(&arg_esp_path, optarg);
    1107         [ #  # ]:          0 :                         if (r < 0)
    1108                 :          0 :                                 return log_oom();
    1109                 :          0 :                         break;
    1110                 :            : 
    1111                 :          0 :                 case ARG_BOOT_PATH:
    1112                 :          0 :                         r = free_and_strdup(&arg_xbootldr_path, optarg);
    1113         [ #  # ]:          0 :                         if (r < 0)
    1114                 :          0 :                                 return log_oom();
    1115                 :          0 :                         break;
    1116                 :            : 
    1117                 :          0 :                 case 'p':
    1118         [ #  # ]:          0 :                         if (arg_print_dollar_boot_path)
    1119         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1120                 :            :                                                        "--print-boot-path/-x cannot be combined with --print-esp-path/-p");
    1121                 :          0 :                         arg_print_esp_path = true;
    1122                 :          0 :                         break;
    1123                 :            : 
    1124                 :          0 :                 case 'x':
    1125         [ #  # ]:          0 :                         if (arg_print_esp_path)
    1126         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1127                 :            :                                                        "--print-boot-path/-x cannot be combined with --print-esp-path/-p");
    1128                 :          0 :                         arg_print_dollar_boot_path = true;
    1129                 :          0 :                         break;
    1130                 :            : 
    1131                 :          0 :                 case ARG_NO_VARIABLES:
    1132                 :          0 :                         arg_touch_variables = false;
    1133                 :          0 :                         break;
    1134                 :            : 
    1135                 :          0 :                 case ARG_NO_PAGER:
    1136                 :          0 :                         arg_pager_flags |= PAGER_DISABLE;
    1137                 :          0 :                         break;
    1138                 :            : 
    1139                 :          4 :                 case '?':
    1140                 :          4 :                         return -EINVAL;
    1141                 :            : 
    1142                 :          0 :                 default:
    1143                 :          0 :                         assert_not_reached("Unknown option");
    1144                 :            :                 }
    1145                 :            : 
    1146                 :          0 :         return 1;
    1147                 :            : }
    1148                 :            : 
    1149                 :          0 : static void read_loader_efi_var(const char *name, char **var) {
    1150                 :            :         int r;
    1151                 :            : 
    1152                 :          0 :         r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
    1153   [ #  #  #  # ]:          0 :         if (r < 0 && r != -ENOENT)
    1154         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
    1155                 :          0 : }
    1156                 :            : 
    1157                 :          0 : static int verb_status(int argc, char *argv[], void *userdata) {
    1158                 :          0 :         sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
    1159                 :            :         int r, k;
    1160                 :            : 
    1161                 :          0 :         r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &esp_uuid);
    1162         [ #  # ]:          0 :         if (arg_print_esp_path) {
    1163         [ #  # ]:          0 :                 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
    1164                 :            :                                    * error the find_esp_and_warn() won't log on its own) */
    1165         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to determine ESP location: %m");
    1166         [ #  # ]:          0 :                 if (r < 0)
    1167                 :          0 :                         return r;
    1168                 :            : 
    1169                 :          0 :                 puts(arg_esp_path);
    1170                 :            :         }
    1171                 :            : 
    1172                 :          0 :         r = acquire_xbootldr(geteuid() != 0, &xbootldr_uuid);
    1173         [ #  # ]:          0 :         if (arg_print_dollar_boot_path) {
    1174         [ #  # ]:          0 :                 if (r == -EACCES)
    1175         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to determine XBOOTLDR location: %m");
    1176         [ #  # ]:          0 :                 if (r < 0)
    1177                 :          0 :                         return r;
    1178                 :            : 
    1179                 :          0 :                 const char *path = arg_dollar_boot_path();
    1180         [ #  # ]:          0 :                 if (!path)
    1181         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EACCES), "Failed to determine XBOOTLDR location: %m");
    1182                 :            : 
    1183                 :          0 :                 puts(path);
    1184                 :            :         }
    1185                 :            : 
    1186   [ #  #  #  # ]:          0 :         if (arg_print_esp_path || arg_print_dollar_boot_path)
    1187                 :          0 :                 return 0;
    1188                 :            : 
    1189                 :          0 :         r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
    1190                 :            :                 * can show */
    1191                 :            : 
    1192                 :          0 :         (void) pager_open(arg_pager_flags);
    1193                 :            : 
    1194         [ #  # ]:          0 :         if (is_efi_boot()) {
    1195                 :            :                 static const struct {
    1196                 :            :                         uint64_t flag;
    1197                 :            :                         const char *name;
    1198                 :            :                 } flags[] = {
    1199                 :            :                         { EFI_LOADER_FEATURE_BOOT_COUNTING,           "Boot counting"                         },
    1200                 :            :                         { EFI_LOADER_FEATURE_CONFIG_TIMEOUT,          "Menu timeout control"                  },
    1201                 :            :                         { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control"         },
    1202                 :            :                         { EFI_LOADER_FEATURE_ENTRY_DEFAULT,           "Default entry control"                 },
    1203                 :            :                         { EFI_LOADER_FEATURE_ENTRY_ONESHOT,           "One-shot entry control"                },
    1204                 :            :                         { EFI_LOADER_FEATURE_XBOOTLDR,                "Support for XBOOTLDR partition"        },
    1205                 :            :                         { EFI_LOADER_FEATURE_RANDOM_SEED,             "Support for passing random seed to OS" },
    1206                 :            :                 };
    1207                 :            : 
    1208   [ #  #  #  #  :          0 :                 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
          #  #  #  #  #  
                      # ]
    1209                 :          0 :                 sd_id128_t loader_part_uuid = SD_ID128_NULL;
    1210                 :          0 :                 uint64_t loader_features = 0;
    1211                 :            :                 size_t i;
    1212                 :            : 
    1213                 :          0 :                 read_loader_efi_var("LoaderFirmwareType", &fw_type);
    1214                 :          0 :                 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
    1215                 :          0 :                 read_loader_efi_var("LoaderInfo", &loader);
    1216                 :          0 :                 read_loader_efi_var("StubInfo", &stub);
    1217                 :          0 :                 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
    1218                 :          0 :                 (void) efi_loader_get_features(&loader_features);
    1219                 :            : 
    1220         [ #  # ]:          0 :                 if (loader_path)
    1221                 :          0 :                         efi_tilt_backslashes(loader_path);
    1222                 :            : 
    1223                 :          0 :                 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
    1224   [ #  #  #  # ]:          0 :                 if (k < 0 && k != -ENOENT)
    1225         [ #  # ]:          0 :                         r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
    1226                 :            : 
    1227                 :          0 :                 printf("System:\n");
    1228                 :          0 :                 printf("     Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal());
    1229                 :          0 :                 printf("  Secure Boot: %sd\n", enable_disable(is_efi_secure_boot()));
    1230         [ #  # ]:          0 :                 printf("   Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user");
    1231                 :          0 :                 printf("\n");
    1232                 :            : 
    1233                 :          0 :                 printf("Current Boot Loader:\n");
    1234                 :          0 :                 printf("      Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
    1235                 :            : 
    1236         [ #  # ]:          0 :                 for (i = 0; i < ELEMENTSOF(flags); i++) {
    1237                 :            : 
    1238         [ #  # ]:          0 :                         if (i == 0)
    1239                 :          0 :                                 printf("     Features: ");
    1240                 :            :                         else
    1241                 :          0 :                                 printf("               ");
    1242                 :            : 
    1243         [ #  # ]:          0 :                         if (FLAGS_SET(loader_features, flags[i].flag))
    1244                 :          0 :                                 printf("%s%s%s %s\n", ansi_highlight_green(), special_glyph(SPECIAL_GLYPH_CHECK_MARK), ansi_normal(), flags[i].name);
    1245                 :            :                         else
    1246                 :          0 :                                 printf("%s%s%s %s\n", ansi_highlight_red(), special_glyph(SPECIAL_GLYPH_CROSS_MARK), ansi_normal(), flags[i].name);
    1247                 :            :                 }
    1248                 :            : 
    1249         [ #  # ]:          0 :                 if (stub)
    1250                 :          0 :                         printf("         Stub: %s\n", stub);
    1251         [ #  # ]:          0 :                 if (!sd_id128_is_null(loader_part_uuid))
    1252                 :          0 :                         printf("          ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
    1253                 :          0 :                                SD_ID128_FORMAT_VAL(loader_part_uuid));
    1254                 :            :                 else
    1255                 :          0 :                         printf("          ESP: n/a\n");
    1256                 :          0 :                 printf("         File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
    1257                 :          0 :                 printf("\n");
    1258                 :            : 
    1259                 :          0 :                 printf("Random Seed:\n");
    1260                 :          0 :                 printf(" Passed to OS: %s\n", yes_no(access("/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f", F_OK) >= 0));
    1261         [ #  # ]:          0 :                 printf(" System Token: %s\n", access("/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f", F_OK) >= 0 ? "set" : "not set");
    1262                 :            : 
    1263         [ #  # ]:          0 :                 if (arg_esp_path) {
    1264         [ #  # ]:          0 :                         _cleanup_free_ char *p = NULL;
    1265                 :            : 
    1266                 :          0 :                         p = path_join(arg_esp_path, "/loader/random-seed");
    1267         [ #  # ]:          0 :                         if (!p)
    1268                 :          0 :                                 return log_oom();
    1269                 :            : 
    1270                 :          0 :                         printf("       Exists: %s\n", yes_no(access(p, F_OK) >= 0));
    1271                 :            :                 }
    1272                 :            : 
    1273                 :          0 :                 printf("\n");
    1274                 :            :         } else
    1275                 :          0 :                 printf("System:\n    Not booted with EFI\n\n");
    1276                 :            : 
    1277         [ #  # ]:          0 :         if (arg_esp_path) {
    1278                 :          0 :                 k = status_binaries(arg_esp_path, esp_uuid);
    1279         [ #  # ]:          0 :                 if (k < 0)
    1280                 :          0 :                         r = k;
    1281                 :            :         }
    1282                 :            : 
    1283         [ #  # ]:          0 :         if (is_efi_boot()) {
    1284                 :          0 :                 k = status_variables();
    1285         [ #  # ]:          0 :                 if (k < 0)
    1286                 :          0 :                         r = k;
    1287                 :            :         }
    1288                 :            : 
    1289   [ #  #  #  # ]:          0 :         if (arg_esp_path || arg_xbootldr_path) {
    1290                 :          0 :                 k = status_entries(arg_esp_path, esp_uuid, arg_xbootldr_path, xbootldr_uuid);
    1291         [ #  # ]:          0 :                 if (k < 0)
    1292                 :          0 :                         r = k;
    1293                 :            :         }
    1294                 :            : 
    1295                 :          0 :         return r;
    1296                 :            : }
    1297                 :            : 
    1298                 :          0 : static int verb_list(int argc, char *argv[], void *userdata) {
    1299                 :          0 :         _cleanup_(boot_config_free) BootConfig config = {};
    1300                 :            :         int r;
    1301                 :            : 
    1302                 :            :         /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
    1303                 :            :          * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
    1304                 :            :          * the latter but not the former, hence request the mode, and log about EACCES. */
    1305                 :            : 
    1306                 :          0 :         r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, NULL);
    1307         [ #  # ]:          0 :         if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
    1308         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to determine ESP: %m");
    1309         [ #  # ]:          0 :         if (r < 0)
    1310                 :          0 :                 return r;
    1311                 :            : 
    1312                 :          0 :         r = acquire_xbootldr(geteuid() != 0, NULL);
    1313         [ #  # ]:          0 :         if (r == -EACCES)
    1314         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
    1315         [ #  # ]:          0 :         if (r < 0)
    1316                 :          0 :                 return r;
    1317                 :            : 
    1318                 :          0 :         r = boot_entries_load_config(arg_esp_path, arg_xbootldr_path, &config);
    1319         [ #  # ]:          0 :         if (r < 0)
    1320                 :          0 :                 return r;
    1321                 :            : 
    1322                 :          0 :         (void) boot_entries_augment_from_loader(&config, false);
    1323                 :            : 
    1324         [ #  # ]:          0 :         if (config.n_entries == 0)
    1325         [ #  # ]:          0 :                 log_info("No boot loader entries found.");
    1326                 :            :         else {
    1327                 :            :                 size_t n;
    1328                 :            : 
    1329                 :          0 :                 (void) pager_open(arg_pager_flags);
    1330                 :            : 
    1331                 :          0 :                 printf("Boot Loader Entries:\n");
    1332                 :            : 
    1333         [ #  # ]:          0 :                 for (n = 0; n < config.n_entries; n++) {
    1334                 :          0 :                         r = boot_entry_show(config.entries + n, n == (size_t) config.default_entry);
    1335         [ #  # ]:          0 :                         if (r < 0)
    1336                 :          0 :                                 return r;
    1337                 :            : 
    1338         [ #  # ]:          0 :                         if (n+1 < config.n_entries)
    1339                 :          0 :                                 putchar('\n');
    1340                 :            :                 }
    1341                 :            :         }
    1342                 :            : 
    1343                 :          0 :         return 0;
    1344                 :            : }
    1345                 :            : 
    1346                 :          0 : static int install_random_seed(const char *esp) {
    1347                 :          0 :         _cleanup_(unlink_and_freep) char *tmp = NULL;
    1348                 :          0 :         _cleanup_free_ void *buffer = NULL;
    1349                 :          0 :         _cleanup_free_ char *path = NULL;
    1350                 :          0 :         _cleanup_close_ int fd = -1;
    1351                 :            :         size_t sz, token_size;
    1352                 :            :         ssize_t n;
    1353                 :            :         int r;
    1354                 :            : 
    1355         [ #  # ]:          0 :         assert(esp);
    1356                 :            : 
    1357                 :          0 :         path = path_join(esp, "/loader/random-seed");
    1358         [ #  # ]:          0 :         if (!path)
    1359                 :          0 :                 return log_oom();
    1360                 :            : 
    1361                 :          0 :         sz = random_pool_size();
    1362                 :            : 
    1363                 :          0 :         buffer = malloc(sz);
    1364         [ #  # ]:          0 :         if (!buffer)
    1365                 :          0 :                 return log_oom();
    1366                 :            : 
    1367                 :          0 :         r = genuine_random_bytes(buffer, sz, RANDOM_BLOCK);
    1368         [ #  # ]:          0 :         if (r < 0)
    1369         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to acquire random seed: %m");
    1370                 :            : 
    1371                 :          0 :         r = tempfn_random(path, "bootctl", &tmp);
    1372         [ #  # ]:          0 :         if (r < 0)
    1373                 :          0 :                 return log_oom();
    1374                 :            : 
    1375                 :          0 :         fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
    1376         [ #  # ]:          0 :         if (fd < 0) {
    1377                 :          0 :                 tmp = mfree(tmp);
    1378         [ #  # ]:          0 :                 return log_error_errno(fd, "Failed to open random seed file for writing: %m");
    1379                 :            :         }
    1380                 :            : 
    1381                 :          0 :         n = write(fd, buffer, sz);
    1382         [ #  # ]:          0 :         if (n < 0)
    1383         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to write random seed file: %m");
    1384         [ #  # ]:          0 :         if ((size_t) n != sz)
    1385         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
    1386                 :            : 
    1387         [ #  # ]:          0 :         if (rename(tmp, path) < 0)
    1388         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to move random seed file into place: %m");
    1389                 :            : 
    1390                 :          0 :         tmp = mfree(tmp);
    1391                 :            : 
    1392         [ #  # ]:          0 :         log_info("Random seed file %s successfully written (%zu bytes).", path, sz);
    1393                 :            : 
    1394         [ #  # ]:          0 :         if (!arg_touch_variables)
    1395                 :          0 :                 return 0;
    1396                 :            : 
    1397         [ #  # ]:          0 :         if (!is_efi_boot()) {
    1398         [ #  # ]:          0 :                 log_notice("Not booted with EFI, skipping EFI variable setup.");
    1399                 :          0 :                 return 0;
    1400                 :            :         }
    1401                 :            : 
    1402                 :          0 :         r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
    1403         [ #  # ]:          0 :         if (r < 0) {
    1404         [ #  # ]:          0 :                 if (r != -ENXIO)
    1405         [ #  # ]:          0 :                          log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
    1406                 :            : 
    1407         [ #  # ]:          0 :                 if (detect_vm() > 0) {
    1408                 :            :                         /* Let's not write a system token if we detect we are running in a VM
    1409                 :            :                          * environment. Why? Our default security model for the random seed uses the system
    1410                 :            :                          * token as a mechanism to ensure we are not vulnerable to golden master sloppiness
    1411                 :            :                          * issues, i.e. that people initialize the random seed file, then copy the image to
    1412                 :            :                          * many systems and end up with the same random seed in each that is assumed to be
    1413                 :            :                          * valid but in reality is the same for all machines. By storing a system token in
    1414                 :            :                          * the EFI variable space we can make sure that even though the random seeds on disk
    1415                 :            :                          * are all the same they will be different on each system under the assumption that
    1416                 :            :                          * the EFI variable space is maintained separate from the random seed storage. That
    1417                 :            :                          * is generally the case on physical systems, as the ESP is stored on persistant
    1418                 :            :                          * storage, and the EFI variables in NVRAM. However in virtualized environments this
    1419                 :            :                          * is generally not true: the EFI variable set is typically stored along with the
    1420                 :            :                          * disk image itself. For example, using the OVMF EFI firmware the EFI variables are
    1421                 :            :                          * stored in a file in the ESP itself. */
    1422                 :            : 
    1423         [ #  # ]:          0 :                         log_notice("Not installing system token, since we are running in a virtualized environment.");
    1424                 :          0 :                         return 0;
    1425                 :            :                 }
    1426         [ #  # ]:          0 :         } else if (r == 0) {
    1427         [ #  # ]:          0 :                 log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
    1428                 :          0 :                 return 0;
    1429                 :            :         }
    1430                 :            : 
    1431                 :          0 :         r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderSystemToken", NULL, NULL, &token_size);
    1432         [ #  # ]:          0 :         if (r < 0) {
    1433         [ #  # ]:          0 :                 if (r != -ENOENT)
    1434         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to test system token validity: %m");
    1435                 :            :         } else {
    1436         [ #  # ]:          0 :                 if (token_size >= sz) {
    1437                 :            :                         /* Let's avoid writes if we can, and initialize this only once. */
    1438         [ #  # ]:          0 :                         log_debug("System token already written, not updating.");
    1439                 :          0 :                         return 0;
    1440                 :            :                 }
    1441                 :            : 
    1442         [ #  # ]:          0 :                 log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sz);
    1443                 :            :         }
    1444                 :            : 
    1445                 :          0 :         r = genuine_random_bytes(buffer, sz, RANDOM_BLOCK);
    1446         [ #  # ]:          0 :         if (r < 0)
    1447         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to acquire random seed: %m");
    1448                 :            : 
    1449                 :            :         /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
    1450                 :            :          * and possibly get identification information or too much insight into the kernel's entropy pool
    1451                 :            :          * state. */
    1452   [ #  #  #  # ]:          0 :         RUN_WITH_UMASK(0077) {
    1453                 :          0 :                 r = efi_set_variable(EFI_VENDOR_LOADER, "LoaderSystemToken", buffer, sz);
    1454         [ #  # ]:          0 :                 if (r < 0)
    1455         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to set LoaderSystemToken EFI variable: %m");
    1456                 :            :         }
    1457                 :            : 
    1458         [ #  # ]:          0 :         log_info("Successfully initialized system token in EFI variable with %zu bytes.", sz);
    1459                 :          0 :         return 0;
    1460                 :            : }
    1461                 :            : 
    1462                 :          0 : static int sync_everything(void) {
    1463                 :          0 :         int ret = 0, k;
    1464                 :            : 
    1465         [ #  # ]:          0 :         if (arg_esp_path) {
    1466                 :          0 :                 k = syncfs_path(AT_FDCWD, arg_esp_path);
    1467         [ #  # ]:          0 :                 if (k < 0)
    1468         [ #  # ]:          0 :                         ret = log_error_errno(k, "Failed to synchronize the ESP '%s': %m", arg_esp_path);
    1469                 :            :         }
    1470                 :            : 
    1471         [ #  # ]:          0 :         if (arg_xbootldr_path) {
    1472                 :          0 :                 k = syncfs_path(AT_FDCWD, arg_xbootldr_path);
    1473         [ #  # ]:          0 :                 if (k < 0)
    1474         [ #  # ]:          0 :                         ret = log_error_errno(k, "Failed to synchronize $BOOT '%s': %m", arg_xbootldr_path);
    1475                 :            :         }
    1476                 :            : 
    1477                 :          0 :         return ret;
    1478                 :            : }
    1479                 :            : 
    1480                 :          0 : static int verb_install(int argc, char *argv[], void *userdata) {
    1481                 :          0 :         sd_id128_t uuid = SD_ID128_NULL;
    1482                 :          0 :         uint64_t pstart = 0, psize = 0;
    1483                 :          0 :         uint32_t part = 0;
    1484                 :            :         sd_id128_t machine_id;
    1485                 :            :         bool install;
    1486                 :            :         int r;
    1487                 :            : 
    1488                 :          0 :         r = acquire_esp(false, &part, &pstart, &psize, &uuid);
    1489         [ #  # ]:          0 :         if (r < 0)
    1490                 :          0 :                 return r;
    1491                 :            : 
    1492                 :          0 :         r = acquire_xbootldr(false, NULL);
    1493         [ #  # ]:          0 :         if (r < 0)
    1494                 :          0 :                 return r;
    1495                 :            : 
    1496                 :          0 :         r = sd_id128_get_machine(&machine_id);
    1497         [ #  # ]:          0 :         if (r < 0)
    1498         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get machine id: %m");
    1499                 :            : 
    1500                 :          0 :         install = streq(argv[0], "install");
    1501                 :            : 
    1502   [ #  #  #  # ]:          0 :         RUN_WITH_UMASK(0002) {
    1503         [ #  # ]:          0 :                 if (install) {
    1504                 :            :                         /* Don't create any of these directories when we are just updating. When we update
    1505                 :            :                          * we'll drop-in our files (unless there are newer ones already), but we won't create
    1506                 :            :                          * the directories for them in the first place. */
    1507                 :          0 :                         r = create_subdirs(arg_esp_path, esp_subdirs);
    1508         [ #  # ]:          0 :                         if (r < 0)
    1509                 :          0 :                                 return r;
    1510                 :            : 
    1511                 :          0 :                         r = create_subdirs(arg_dollar_boot_path(), dollar_boot_subdirs);
    1512         [ #  # ]:          0 :                         if (r < 0)
    1513                 :          0 :                                 return r;
    1514                 :            :                 }
    1515                 :            : 
    1516                 :          0 :                 r = install_binaries(arg_esp_path, install);
    1517         [ #  # ]:          0 :                 if (r < 0)
    1518                 :          0 :                         return r;
    1519                 :            : 
    1520         [ #  # ]:          0 :                 if (install) {
    1521                 :          0 :                         r = install_loader_config(arg_esp_path, machine_id);
    1522         [ #  # ]:          0 :                         if (r < 0)
    1523                 :          0 :                                 return r;
    1524                 :            : 
    1525                 :          0 :                         r = install_machine_id_directory(arg_dollar_boot_path(), machine_id);
    1526         [ #  # ]:          0 :                         if (r < 0)
    1527                 :          0 :                                 return r;
    1528                 :            : 
    1529                 :          0 :                         r = install_random_seed(arg_esp_path);
    1530         [ #  # ]:          0 :                         if (r < 0)
    1531                 :          0 :                                 return r;
    1532                 :            :                 }
    1533                 :            :         }
    1534                 :            : 
    1535                 :          0 :         (void) sync_everything();
    1536                 :            : 
    1537         [ #  # ]:          0 :         if (arg_touch_variables)
    1538                 :          0 :                 r = install_variables(arg_esp_path,
    1539                 :            :                                       part, pstart, psize, uuid,
    1540                 :            :                                       "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
    1541                 :            :                                       install);
    1542                 :            : 
    1543                 :          0 :         return r;
    1544                 :            : }
    1545                 :            : 
    1546                 :          0 : static int verb_remove(int argc, char *argv[], void *userdata) {
    1547                 :          0 :         sd_id128_t uuid = SD_ID128_NULL, machine_id;
    1548                 :            :         int r, q;
    1549                 :            : 
    1550                 :          0 :         r = acquire_esp(false, NULL, NULL, NULL, &uuid);
    1551         [ #  # ]:          0 :         if (r < 0)
    1552                 :          0 :                 return r;
    1553                 :            : 
    1554                 :          0 :         r = acquire_xbootldr(false, NULL);
    1555         [ #  # ]:          0 :         if (r < 0)
    1556                 :          0 :                 return r;
    1557                 :            : 
    1558                 :          0 :         r = sd_id128_get_machine(&machine_id);
    1559         [ #  # ]:          0 :         if (r < 0)
    1560         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get machine id: %m");
    1561                 :            : 
    1562                 :          0 :         r = remove_binaries(arg_esp_path);
    1563                 :            : 
    1564                 :          0 :         q = remove_file(arg_esp_path, "/loader/loader.conf");
    1565   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1566                 :          0 :                 r = q;
    1567                 :            : 
    1568                 :          0 :         q = remove_file(arg_esp_path, "/loader/random-seed");
    1569   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1570                 :          0 :                 r = q;
    1571                 :            : 
    1572                 :          0 :         q = remove_subdirs(arg_esp_path, esp_subdirs);
    1573   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1574                 :          0 :                 r = q;
    1575                 :            : 
    1576                 :          0 :         q = remove_subdirs(arg_esp_path, dollar_boot_subdirs);
    1577   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1578                 :          0 :                 r = q;
    1579                 :            : 
    1580                 :          0 :         q = remove_machine_id_directory(arg_esp_path, machine_id);
    1581   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1582                 :          0 :                 r = 1;
    1583                 :            : 
    1584         [ #  # ]:          0 :         if (arg_xbootldr_path) {
    1585                 :            :                 /* Remove the latter two also in the XBOOTLDR partition if it exists */
    1586                 :          0 :                 q = remove_subdirs(arg_xbootldr_path, dollar_boot_subdirs);
    1587   [ #  #  #  # ]:          0 :                 if (q < 0 && r >= 0)
    1588                 :          0 :                         r = q;
    1589                 :            : 
    1590                 :          0 :                 q = remove_machine_id_directory(arg_xbootldr_path, machine_id);
    1591   [ #  #  #  # ]:          0 :                 if (q < 0 && r >= 0)
    1592                 :          0 :                         r = q;
    1593                 :            :         }
    1594                 :            : 
    1595                 :          0 :         (void) sync_everything();
    1596                 :            : 
    1597         [ #  # ]:          0 :         if (!arg_touch_variables)
    1598                 :          0 :                 return r;
    1599                 :            : 
    1600                 :          0 :         q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
    1601   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1602                 :          0 :                 r = q;
    1603                 :            : 
    1604                 :          0 :         q = remove_loader_variables();
    1605   [ #  #  #  # ]:          0 :         if (q < 0 && r >= 0)
    1606                 :          0 :                 r = q;
    1607                 :            : 
    1608                 :          0 :         return r;
    1609                 :            : }
    1610                 :            : 
    1611                 :          0 : static int verb_is_installed(int argc, char *argv[], void *userdata) {
    1612                 :          0 :         _cleanup_free_ char *p = NULL;
    1613                 :            :         int r;
    1614                 :            : 
    1615                 :          0 :         r = acquire_esp(false, NULL, NULL, NULL, NULL);
    1616         [ #  # ]:          0 :         if (r < 0)
    1617                 :          0 :                 return r;
    1618                 :            : 
    1619                 :            :         /* Tests whether systemd-boot is installed. It's not obvious what to use as check here: we could
    1620                 :            :          * check EFI variables, we could check what binary /EFI/BOOT/BOOT*.EFI points to, or whether the
    1621                 :            :          * loader entries directory exists. Here we opted to check whether /EFI/systemd/ is non-empty, which
    1622                 :            :          * should be a suitable and very minimal check for a number of reasons:
    1623                 :            :          *
    1624                 :            :          *  → The check is architecture independent (i.e. we check if any systemd-boot loader is installed, not a
    1625                 :            :          *    specific one.)
    1626                 :            :          *
    1627                 :            :          *  → It doesn't assume we are the only boot loader (i.e doesn't check if we own the main
    1628                 :            :          *    /EFI/BOOT/BOOT*.EFI fallback binary.
    1629                 :            :          *
    1630                 :            :          *  → It specifically checks for systemd-boot, not for other boot loaders (which a check for
    1631                 :            :          *    /boot/loader/entries would do). */
    1632                 :            : 
    1633                 :          0 :         p = path_join(arg_esp_path, "/EFI/systemd/");
    1634         [ #  # ]:          0 :         if (!p)
    1635                 :          0 :                 return log_oom();
    1636                 :            : 
    1637                 :          0 :         r = dir_is_empty(p);
    1638   [ #  #  #  # ]:          0 :         if (r > 0 || r == -ENOENT) {
    1639                 :          0 :                 puts("no");
    1640                 :          0 :                 return EXIT_FAILURE;
    1641                 :            :         }
    1642         [ #  # ]:          0 :         if (r < 0)
    1643         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to detect whether systemd-boot is installed: %m");
    1644                 :            : 
    1645                 :          0 :         puts("yes");
    1646                 :          0 :         return EXIT_SUCCESS;
    1647                 :            : }
    1648                 :            : 
    1649                 :          0 : static int verb_set_default(int argc, char *argv[], void *userdata) {
    1650                 :            :         const char *name;
    1651                 :            :         int r;
    1652                 :            : 
    1653         [ #  # ]:          0 :         if (!is_efi_boot())
    1654         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
    1655                 :            :                                        "Not booted with UEFI.");
    1656                 :            : 
    1657         [ #  # ]:          0 :         if (access("/sys/firmware/efi/efivars/LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f", F_OK) < 0) {
    1658         [ #  # ]:          0 :                 if (errno == ENOENT) {
    1659         [ #  # ]:          0 :                         log_error_errno(errno, "Not booted with a supported boot loader.");
    1660                 :          0 :                         return -EOPNOTSUPP;
    1661                 :            :                 }
    1662                 :            : 
    1663         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to detect whether boot loader supports '%s' operation: %m", argv[0]);
    1664                 :            :         }
    1665                 :            : 
    1666         [ #  # ]:          0 :         if (detect_container() > 0)
    1667         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
    1668                 :            :                                        "'%s' operation not supported in a container.",
    1669                 :            :                                        argv[0]);
    1670                 :            : 
    1671         [ #  # ]:          0 :         if (!arg_touch_variables)
    1672         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1673                 :            :                                        "'%s' operation cannot be combined with --touch-variables=no.",
    1674                 :            :                                        argv[0]);
    1675                 :            : 
    1676         [ #  # ]:          0 :         name = streq(argv[0], "set-default") ? "LoaderEntryDefault" : "LoaderEntryOneShot";
    1677                 :            : 
    1678         [ #  # ]:          0 :         if (isempty(argv[1])) {
    1679                 :          0 :                 r = efi_set_variable(EFI_VENDOR_LOADER, name, NULL, 0);
    1680   [ #  #  #  # ]:          0 :                 if (r < 0 && r != -ENOENT)
    1681         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to remove EFI variale: %m");
    1682                 :            :         } else {
    1683         [ #  # ]:          0 :                 _cleanup_free_ char16_t *encoded = NULL;
    1684                 :            : 
    1685                 :          0 :                 encoded = utf8_to_utf16(argv[1], strlen(argv[1]));
    1686         [ #  # ]:          0 :                 if (!encoded)
    1687                 :          0 :                         return log_oom();
    1688                 :            : 
    1689                 :          0 :                 r = efi_set_variable(EFI_VENDOR_LOADER, name, encoded, char16_strlen(encoded) * 2 + 2);
    1690         [ #  # ]:          0 :                 if (r < 0)
    1691         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to update EFI variable: %m");
    1692                 :            :         }
    1693                 :            : 
    1694                 :          0 :         return 0;
    1695                 :            : }
    1696                 :            : 
    1697                 :          0 : static int verb_random_seed(int argc, char *argv[], void *userdata) {
    1698                 :            :         int r;
    1699                 :            : 
    1700                 :          0 :         r = acquire_esp(false, NULL, NULL, NULL, NULL);
    1701         [ #  # ]:          0 :         if (r < 0)
    1702                 :          0 :                 return r;
    1703                 :            : 
    1704                 :          0 :         r = install_random_seed(arg_esp_path);
    1705         [ #  # ]:          0 :         if (r < 0)
    1706                 :          0 :                 return r;
    1707                 :            : 
    1708                 :          0 :         (void) sync_everything();
    1709                 :          0 :         return 0;
    1710                 :            : }
    1711                 :            : 
    1712                 :          0 : static int bootctl_main(int argc, char *argv[]) {
    1713                 :            :         static const Verb verbs[] = {
    1714                 :            :                 { "help",         VERB_ANY, VERB_ANY, 0,            help              },
    1715                 :            :                 { "status",       VERB_ANY, 1,        VERB_DEFAULT, verb_status       },
    1716                 :            :                 { "install",      VERB_ANY, 1,        0,            verb_install      },
    1717                 :            :                 { "update",       VERB_ANY, 1,        0,            verb_install      },
    1718                 :            :                 { "remove",       VERB_ANY, 1,        0,            verb_remove       },
    1719                 :            :                 { "random-seed",  VERB_ANY, 1,        0,            verb_random_seed  },
    1720                 :            :                 { "is-installed", VERB_ANY, 1,        0,            verb_is_installed },
    1721                 :            :                 { "list",         VERB_ANY, 1,        0,            verb_list         },
    1722                 :            :                 { "set-default",  2,        2,        0,            verb_set_default  },
    1723                 :            :                 { "set-oneshot",  2,        2,        0,            verb_set_default  },
    1724                 :            :                 {}
    1725                 :            :         };
    1726                 :            : 
    1727                 :          0 :         return dispatch_verb(argc, argv, verbs, NULL);
    1728                 :            : }
    1729                 :            : 
    1730                 :         16 : static int run(int argc, char *argv[]) {
    1731                 :            :         int r;
    1732                 :            : 
    1733                 :         16 :         log_parse_environment();
    1734                 :         16 :         log_open();
    1735                 :            : 
    1736                 :            :         /* If we run in a container, automatically turn off EFI file system access */
    1737         [ -  + ]:         16 :         if (detect_container() > 0)
    1738                 :          0 :                 arg_touch_variables = false;
    1739                 :            : 
    1740                 :         16 :         r = parse_argv(argc, argv);
    1741         [ +  - ]:         16 :         if (r <= 0)
    1742                 :         16 :                 return r;
    1743                 :            : 
    1744                 :          0 :         return bootctl_main(argc, argv);
    1745                 :            : }
    1746                 :            : 
    1747                 :         16 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14