LCOV - code coverage report
Current view: top level - boot - bless-boot.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 265 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 13 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 260 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <getopt.h>
       4                 :            : #include <stdlib.h>
       5                 :            : 
       6                 :            : #include "alloc-util.h"
       7                 :            : #include "bootspec.h"
       8                 :            : #include "efivars.h"
       9                 :            : #include "fd-util.h"
      10                 :            : #include "fs-util.h"
      11                 :            : #include "log.h"
      12                 :            : #include "main-func.h"
      13                 :            : #include "parse-util.h"
      14                 :            : #include "path-util.h"
      15                 :            : #include "util.h"
      16                 :            : #include "verbs.h"
      17                 :            : #include "virt.h"
      18                 :            : 
      19                 :            : static char **arg_path = NULL;
      20                 :            : 
      21                 :          0 : STATIC_DESTRUCTOR_REGISTER(arg_path, strv_freep);
      22                 :            : 
      23                 :          0 : static int help(int argc, char *argv[], void *userdata) {
      24                 :            : 
      25                 :          0 :         printf("%s [COMMAND] [OPTIONS...]\n"
      26                 :            :                "\n"
      27                 :            :                "Mark the boot process as good or bad.\n\n"
      28                 :            :                "  -h --help          Show this help\n"
      29                 :            :                "     --version       Print version\n"
      30                 :            :                "     --path=PATH     Path to the $BOOT partition (may be used multiple times)\n"
      31                 :            :                "\n"
      32                 :            :                "Commands:\n"
      33                 :            :                "     good            Mark this boot as good\n"
      34                 :            :                "     bad             Mark this boot as bad\n"
      35                 :            :                "     indeterminate   Undo any marking as good or bad\n",
      36                 :            :                program_invocation_short_name);
      37                 :            : 
      38                 :          0 :         return 0;
      39                 :            : }
      40                 :            : 
      41                 :          0 : static int parse_argv(int argc, char *argv[]) {
      42                 :            :         enum {
      43                 :            :                 ARG_PATH = 0x100,
      44                 :            :                 ARG_VERSION,
      45                 :            :         };
      46                 :            : 
      47                 :            :         static const struct option options[] = {
      48                 :            :                 { "help",         no_argument,       NULL, 'h'              },
      49                 :            :                 { "version",      no_argument,       NULL, ARG_VERSION      },
      50                 :            :                 { "path",         required_argument, NULL, ARG_PATH         },
      51                 :            :                 {}
      52                 :            :         };
      53                 :            : 
      54                 :            :         int c, r;
      55                 :            : 
      56         [ #  # ]:          0 :         assert(argc >= 0);
      57         [ #  # ]:          0 :         assert(argv);
      58                 :            : 
      59         [ #  # ]:          0 :         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
      60   [ #  #  #  #  :          0 :                 switch (c) {
                      # ]
      61                 :            : 
      62                 :          0 :                 case 'h':
      63                 :          0 :                         help(0, NULL, NULL);
      64                 :          0 :                         return 0;
      65                 :            : 
      66                 :          0 :                 case ARG_VERSION:
      67                 :          0 :                         return version();
      68                 :            : 
      69                 :          0 :                 case ARG_PATH:
      70                 :          0 :                         r = strv_extend(&arg_path, optarg);
      71         [ #  # ]:          0 :                         if (r < 0)
      72                 :          0 :                                 return log_oom();
      73                 :          0 :                         break;
      74                 :            : 
      75                 :          0 :                 case '?':
      76                 :          0 :                         return -EINVAL;
      77                 :            : 
      78                 :          0 :                 default:
      79                 :          0 :                         assert_not_reached("Unknown option");
      80                 :            :                 }
      81                 :            : 
      82                 :          0 :         return 1;
      83                 :            : }
      84                 :            : 
      85                 :          0 : static int acquire_path(void) {
      86                 :          0 :         _cleanup_free_ char *esp_path = NULL, *xbootldr_path = NULL;
      87                 :            :         char **a;
      88                 :            :         int r;
      89                 :            : 
      90         [ #  # ]:          0 :         if (!strv_isempty(arg_path))
      91                 :          0 :                 return 0;
      92                 :            : 
      93                 :          0 :         r = find_esp_and_warn(NULL, false, &esp_path, NULL, NULL, NULL, NULL);
      94   [ #  #  #  # ]:          0 :         if (r < 0 && r != -ENOKEY) /* ENOKEY means not found, and is the only error the function won't log about on its own */
      95                 :          0 :                 return r;
      96                 :            : 
      97                 :          0 :         r = find_xbootldr_and_warn(NULL, false, &xbootldr_path, NULL);
      98   [ #  #  #  # ]:          0 :         if (r < 0 && r != -ENOKEY)
      99                 :          0 :                 return r;
     100                 :            : 
     101   [ #  #  #  # ]:          0 :         if (!esp_path && !xbootldr_path)
     102         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
     103                 :            :                                        "Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n"
     104                 :            :                                        "Alternatively, use --path= to specify path to mount point.");
     105                 :            : 
     106         [ #  # ]:          0 :         if (esp_path)
     107                 :          0 :                 a = strv_new(esp_path, xbootldr_path);
     108                 :            :         else
     109                 :          0 :                 a = strv_new(xbootldr_path);
     110         [ #  # ]:          0 :         if (!a)
     111                 :          0 :                 return log_oom();
     112                 :            : 
     113                 :          0 :         strv_free_and_replace(arg_path, a);
     114                 :            : 
     115         [ #  # ]:          0 :         if (DEBUG_LOGGING) {
     116                 :          0 :                 _cleanup_free_ char *j;
     117                 :            : 
     118                 :          0 :                 j = strv_join(arg_path, ":");
     119         [ #  # ]:          0 :                 log_debug("Using %s as boot loader drop-in search path.", j);
     120                 :            :         }
     121                 :            : 
     122                 :          0 :         return 0;
     123                 :            : }
     124                 :            : 
     125                 :          0 : static int parse_counter(
     126                 :            :                 const char *path,
     127                 :            :                 const char **p,
     128                 :            :                 uint64_t *ret_left,
     129                 :            :                 uint64_t *ret_done) {
     130                 :            : 
     131                 :            :         uint64_t left, done;
     132                 :            :         const char *z, *e;
     133                 :            :         size_t k;
     134                 :            :         int r;
     135                 :            : 
     136         [ #  # ]:          0 :         assert(path);
     137         [ #  # ]:          0 :         assert(p);
     138                 :            : 
     139                 :          0 :         e = *p;
     140         [ #  # ]:          0 :         assert(e);
     141         [ #  # ]:          0 :         assert(*e == '+');
     142                 :            : 
     143                 :          0 :         e++;
     144                 :            : 
     145                 :          0 :         k = strspn(e, DIGITS);
     146         [ #  # ]:          0 :         if (k == 0)
     147         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     148                 :            :                                        "Can't parse empty 'tries left' counter from LoaderBootCountPath: %s",
     149                 :            :                                        path);
     150                 :            : 
     151                 :          0 :         z = strndupa(e, k);
     152                 :          0 :         r = safe_atou64(z, &left);
     153         [ #  # ]:          0 :         if (r < 0)
     154         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to parse 'tries left' counter from LoaderBootCountPath: %s", path);
     155                 :            : 
     156                 :          0 :         e += k;
     157                 :            : 
     158         [ #  # ]:          0 :         if (*e == '-') {
     159                 :          0 :                 e++;
     160                 :            : 
     161                 :          0 :                 k = strspn(e, DIGITS);
     162         [ #  # ]:          0 :                 if (k == 0) /* If there's a "-" there also needs to be at least one digit */
     163         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     164                 :            :                                                "Can't parse empty 'tries done' counter from LoaderBootCountPath: %s",
     165                 :            :                                                path);
     166                 :            : 
     167                 :          0 :                 z = strndupa(e, k);
     168                 :          0 :                 r = safe_atou64(z, &done);
     169         [ #  # ]:          0 :                 if (r < 0)
     170         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to parse 'tries done' counter from LoaderBootCountPath: %s", path);
     171                 :            : 
     172                 :          0 :                 e += k;
     173                 :            :         } else
     174                 :          0 :                 done = 0;
     175                 :            : 
     176         [ #  # ]:          0 :         if (done == 0)
     177         [ #  # ]:          0 :                 log_warning("The 'tries done' counter is currently at zero. This can't really be, after all we are running, and this boot must hence count as one. Proceeding anyway.");
     178                 :            : 
     179                 :          0 :         *p = e;
     180                 :            : 
     181         [ #  # ]:          0 :         if (ret_left)
     182                 :          0 :                 *ret_left = left;
     183                 :            : 
     184         [ #  # ]:          0 :         if (ret_done)
     185                 :          0 :                 *ret_done = done;
     186                 :            : 
     187                 :          0 :         return 0;
     188                 :            : }
     189                 :            : 
     190                 :          0 : static int acquire_boot_count_path(
     191                 :            :                 char **ret_path,
     192                 :            :                 char **ret_prefix,
     193                 :            :                 uint64_t *ret_left,
     194                 :            :                 uint64_t *ret_done,
     195                 :            :                 char **ret_suffix) {
     196                 :            : 
     197                 :          0 :         _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL;
     198                 :            :         const char *last, *e;
     199                 :            :         uint64_t left, done;
     200                 :            :         int r;
     201                 :            : 
     202                 :          0 :         r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderBootCountPath", &path);
     203         [ #  # ]:          0 :         if (r == -ENOENT)
     204                 :          0 :                 return -EUNATCH; /* in this case, let the caller print a message */
     205         [ #  # ]:          0 :         if (r < 0)
     206         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to read LoaderBootCountPath EFI variable: %m");
     207                 :            : 
     208                 :          0 :         efi_tilt_backslashes(path);
     209                 :            : 
     210         [ #  # ]:          0 :         if (!path_is_normalized(path))
     211         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     212                 :            :                                        "Path read from LoaderBootCountPath is not normalized, refusing: %s",
     213                 :            :                                        path);
     214                 :            : 
     215         [ #  # ]:          0 :         if (!path_is_absolute(path))
     216         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     217                 :            :                                        "Path read from LoaderBootCountPath is not absolute, refusing: %s",
     218                 :            :                                        path);
     219                 :            : 
     220                 :          0 :         last = last_path_component(path);
     221                 :          0 :         e = strrchr(last, '+');
     222         [ #  # ]:          0 :         if (!e)
     223         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     224                 :            :                                        "Path read from LoaderBootCountPath does not contain a counter, refusing: %s",
     225                 :            :                                        path);
     226                 :            : 
     227         [ #  # ]:          0 :         if (ret_prefix) {
     228                 :          0 :                 prefix = strndup(path, e - path);
     229         [ #  # ]:          0 :                 if (!prefix)
     230                 :          0 :                         return log_oom();
     231                 :            :         }
     232                 :            : 
     233                 :          0 :         r = parse_counter(path, &e, &left, &done);
     234         [ #  # ]:          0 :         if (r < 0)
     235                 :          0 :                 return r;
     236                 :            : 
     237         [ #  # ]:          0 :         if (ret_suffix) {
     238                 :          0 :                 suffix = strdup(e);
     239         [ #  # ]:          0 :                 if (!suffix)
     240                 :          0 :                         return log_oom();
     241                 :            : 
     242                 :          0 :                 *ret_suffix = TAKE_PTR(suffix);
     243                 :            :         }
     244                 :            : 
     245         [ #  # ]:          0 :         if (ret_path)
     246                 :          0 :                 *ret_path = TAKE_PTR(path);
     247         [ #  # ]:          0 :         if (ret_prefix)
     248                 :          0 :                 *ret_prefix = TAKE_PTR(prefix);
     249         [ #  # ]:          0 :         if (ret_left)
     250                 :          0 :                 *ret_left = left;
     251         [ #  # ]:          0 :         if (ret_done)
     252                 :          0 :                 *ret_done = done;
     253                 :            : 
     254                 :          0 :         return 0;
     255                 :            : }
     256                 :            : 
     257                 :          0 : static int make_good(const char *prefix, const char *suffix, char **ret) {
     258                 :          0 :         _cleanup_free_ char *good = NULL;
     259                 :            : 
     260         [ #  # ]:          0 :         assert(prefix);
     261         [ #  # ]:          0 :         assert(suffix);
     262         [ #  # ]:          0 :         assert(ret);
     263                 :            : 
     264                 :            :         /* Generate the path we'd use on good boots. This one is easy. If we are successful, we simple drop the counter
     265                 :            :          * pair entirely from the name. After all, we know all is good, and the logs will contain information about the
     266                 :            :          * tries we needed to come here, hence it's safe to drop the counters from the name. */
     267                 :            : 
     268                 :          0 :         good = strjoin(prefix, suffix);
     269         [ #  # ]:          0 :         if (!good)
     270                 :          0 :                 return -ENOMEM;
     271                 :            : 
     272                 :          0 :         *ret = TAKE_PTR(good);
     273                 :          0 :         return 0;
     274                 :            : }
     275                 :            : 
     276                 :          0 : static int make_bad(const char *prefix, uint64_t done, const char *suffix, char **ret) {
     277                 :          0 :         _cleanup_free_ char *bad = NULL;
     278                 :            : 
     279         [ #  # ]:          0 :         assert(prefix);
     280         [ #  # ]:          0 :         assert(suffix);
     281         [ #  # ]:          0 :         assert(ret);
     282                 :            : 
     283                 :            :         /* Generate the path we'd use on bad boots. Let's simply set the 'left' counter to zero, and keep the 'done'
     284                 :            :          * counter. The information might be interesting to boot loaders, after all. */
     285                 :            : 
     286         [ #  # ]:          0 :         if (done == 0) {
     287                 :          0 :                 bad = strjoin(prefix, "+0", suffix);
     288         [ #  # ]:          0 :                 if (!bad)
     289                 :          0 :                         return -ENOMEM;
     290                 :            :         } else {
     291         [ #  # ]:          0 :                 if (asprintf(&bad, "%s+0-%" PRIu64 "%s", prefix, done, suffix) < 0)
     292                 :          0 :                         return -ENOMEM;
     293                 :            :         }
     294                 :            : 
     295                 :          0 :         *ret = TAKE_PTR(bad);
     296                 :          0 :         return 0;
     297                 :            : }
     298                 :            : 
     299                 :          0 : static const char *skip_slash(const char *path) {
     300         [ #  # ]:          0 :         assert(path);
     301         [ #  # ]:          0 :         assert(path[0] == '/');
     302                 :            : 
     303                 :          0 :         return path + 1;
     304                 :            : }
     305                 :            : 
     306                 :          0 : static int verb_status(int argc, char *argv[], void *userdata) {
     307                 :          0 :         _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL;
     308                 :            :         uint64_t left, done;
     309                 :            :         char **p;
     310                 :            :         int r;
     311                 :            : 
     312                 :          0 :         r = acquire_boot_count_path(&path, &prefix, &left, &done, &suffix);
     313         [ #  # ]:          0 :         if (r == -EUNATCH) { /* No boot count in place, then let's consider this a "clean" boot, as "good", "bad" or "indeterminate" don't apply. */
     314                 :          0 :                 puts("clean");
     315                 :          0 :                 return 0;
     316                 :            :         }
     317         [ #  # ]:          0 :         if (r < 0)
     318                 :          0 :                 return r;
     319                 :            : 
     320                 :          0 :         r = acquire_path();
     321         [ #  # ]:          0 :         if (r < 0)
     322                 :          0 :                 return r;
     323                 :            : 
     324                 :          0 :         r = make_good(prefix, suffix, &good);
     325         [ #  # ]:          0 :         if (r < 0)
     326                 :          0 :                 return log_oom();
     327                 :            : 
     328                 :          0 :         r = make_bad(prefix, done, suffix, &bad);
     329         [ #  # ]:          0 :         if (r < 0)
     330                 :          0 :                 return log_oom();
     331                 :            : 
     332         [ #  # ]:          0 :         log_debug("Booted file: %s\n"
     333                 :            :                   "The same modified for 'good': %s\n"
     334                 :            :                   "The same modified for 'bad':  %s\n",
     335                 :            :                   path,
     336                 :            :                   good,
     337                 :            :                   bad);
     338                 :            : 
     339         [ #  # ]:          0 :         log_debug("Tries left: %" PRIu64"\n"
     340                 :            :                   "Tries done: %" PRIu64"\n",
     341                 :            :                   left, done);
     342                 :            : 
     343   [ #  #  #  # ]:          0 :         STRV_FOREACH(p, arg_path) {
     344      [ #  #  # ]:          0 :                 _cleanup_close_ int fd = -1;
     345                 :            : 
     346                 :          0 :                 fd = open(*p, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
     347         [ #  # ]:          0 :                 if (fd < 0) {
     348         [ #  # ]:          0 :                         if (errno == ENOENT)
     349                 :          0 :                                 continue;
     350                 :            : 
     351         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
     352                 :            :                 }
     353                 :            : 
     354         [ #  # ]:          0 :                 if (faccessat(fd, skip_slash(path), F_OK, 0) >= 0) {
     355                 :          0 :                         puts("indeterminate");
     356                 :          0 :                         return 0;
     357                 :            :                 }
     358         [ #  # ]:          0 :                 if (errno != ENOENT)
     359         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to check if '%s' exists: %m", path);
     360                 :            : 
     361         [ #  # ]:          0 :                 if (faccessat(fd, skip_slash(good), F_OK, 0) >= 0) {
     362                 :          0 :                         puts("good");
     363                 :          0 :                         return 0;
     364                 :            :                 }
     365                 :            : 
     366         [ #  # ]:          0 :                 if (errno != ENOENT)
     367         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to check if '%s' exists: %m", good);
     368                 :            : 
     369         [ #  # ]:          0 :                 if (faccessat(fd, skip_slash(bad), F_OK, 0) >= 0) {
     370                 :          0 :                         puts("bad");
     371                 :          0 :                         return 0;
     372                 :            :                 }
     373         [ #  # ]:          0 :                 if (errno != ENOENT)
     374         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to check if '%s' exists: %m", bad);
     375                 :            : 
     376                 :            :                 /* We didn't find any of the three? If so, let's try the next directory, before we give up. */
     377                 :            :         }
     378                 :            : 
     379         [ #  # ]:          0 :         return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Couldn't determine boot state: %m");
     380                 :            : }
     381                 :            : 
     382                 :          0 : static int verb_set(int argc, char *argv[], void *userdata) {
     383                 :          0 :         _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL, *parent = NULL;
     384                 :            :         const char *target, *source1, *source2;
     385                 :            :         uint64_t done;
     386                 :            :         char **p;
     387                 :            :         int r;
     388                 :            : 
     389                 :          0 :         r = acquire_boot_count_path(&path, &prefix, NULL, &done, &suffix);
     390         [ #  # ]:          0 :         if (r == -EUNATCH) /* acquire_boot_count_path() won't log on its own for this specific error */
     391         [ #  # ]:          0 :                 return log_error_errno(r, "Not booted with boot counting in effect.");
     392         [ #  # ]:          0 :         if (r < 0)
     393                 :          0 :                 return r;
     394                 :            : 
     395                 :          0 :         r = acquire_path();
     396         [ #  # ]:          0 :         if (r < 0)
     397                 :          0 :                 return r;
     398                 :            : 
     399                 :          0 :         r = make_good(prefix, suffix, &good);
     400         [ #  # ]:          0 :         if (r < 0)
     401                 :          0 :                 return log_oom();
     402                 :            : 
     403                 :          0 :         r = make_bad(prefix, done, suffix, &bad);
     404         [ #  # ]:          0 :         if (r < 0)
     405                 :          0 :                 return log_oom();
     406                 :            : 
     407                 :            :         /* Figure out what rename to what */
     408         [ #  # ]:          0 :         if (streq(argv[0], "good")) {
     409                 :          0 :                 target = good;
     410                 :          0 :                 source1 = path;
     411                 :          0 :                 source2 = bad;      /* Maybe this boot was previously marked as 'bad'? */
     412         [ #  # ]:          0 :         } else if (streq(argv[0], "bad")) {
     413                 :          0 :                 target = bad;
     414                 :          0 :                 source1 = path;
     415                 :          0 :                 source2 = good;     /* Maybe this boot was previously marked as 'good'? */
     416                 :            :         } else {
     417         [ #  # ]:          0 :                 assert(streq(argv[0], "indeterminate"));
     418                 :          0 :                 target = path;
     419                 :          0 :                 source1 = good;
     420                 :          0 :                 source2 = bad;
     421                 :            :         }
     422                 :            : 
     423   [ #  #  #  # ]:          0 :         STRV_FOREACH(p, arg_path) {
     424   [ #  #  #  # ]:          0 :                 _cleanup_close_ int fd = -1;
     425                 :            : 
     426                 :          0 :                 fd = open(*p, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
     427         [ #  # ]:          0 :                 if (fd < 0)
     428         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
     429                 :            : 
     430                 :          0 :                 r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
     431         [ #  # ]:          0 :                 if (r == -EEXIST)
     432                 :          0 :                         goto exists;
     433         [ #  # ]:          0 :                 else if (r == -ENOENT) {
     434                 :            : 
     435                 :          0 :                         r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
     436         [ #  # ]:          0 :                         if (r == -EEXIST)
     437                 :          0 :                                 goto exists;
     438         [ #  # ]:          0 :                         else if (r == -ENOENT) {
     439                 :            : 
     440         [ #  # ]:          0 :                                 if (faccessat(fd, skip_slash(target), F_OK, 0) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
     441                 :          0 :                                         goto exists;
     442                 :            : 
     443         [ #  # ]:          0 :                                 if (errno != ENOENT)
     444         [ #  # ]:          0 :                                         return log_error_errno(errno, "Failed to determine if %s already exists: %m", target);
     445                 :            : 
     446                 :            :                                 /* We found none of the snippets here, try the next directory */
     447                 :          0 :                                 continue;
     448         [ #  # ]:          0 :                         } else if (r < 0)
     449         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source2, target);
     450                 :            :                         else
     451         [ #  # ]:          0 :                                 log_debug("Successfully renamed '%s' to '%s'.", source2, target);
     452                 :            : 
     453         [ #  # ]:          0 :                 } else if (r < 0)
     454         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source1, target);
     455                 :            :                 else
     456         [ #  # ]:          0 :                         log_debug("Successfully renamed '%s' to '%s'.", source1, target);
     457                 :            : 
     458                 :            :                 /* First, fsync() the directory these files are located in */
     459                 :          0 :                 parent = dirname_malloc(target);
     460         [ #  # ]:          0 :                 if (!parent)
     461                 :          0 :                         return log_oom();
     462                 :            : 
     463                 :          0 :                 r = fsync_path_at(fd, skip_slash(parent));
     464         [ #  # ]:          0 :                 if (r < 0)
     465         [ #  # ]:          0 :                         log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
     466                 :            : 
     467                 :            :                 /* Secondly, syncfs() the whole file system these files are located in */
     468         [ #  # ]:          0 :                 if (syncfs(fd) < 0)
     469         [ #  # ]:          0 :                         log_debug_errno(errno, "Failed to synchronize $BOOT partition, ignoring: %m");
     470                 :            : 
     471         [ #  # ]:          0 :                 log_info("Marked boot as '%s'. (Boot attempt counter is at %" PRIu64".)", argv[0], done);
     472                 :            :         }
     473                 :            : 
     474         [ #  # ]:          0 :         log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Can't find boot counter source file for '%s': %m", target);
     475                 :          0 :         return 1;
     476                 :            : 
     477                 :          0 : exists:
     478         [ #  # ]:          0 :         log_debug("Operation already executed before, not doing anything.");
     479                 :          0 :         return 0;
     480                 :            : }
     481                 :            : 
     482                 :          0 : static int run(int argc, char *argv[]) {
     483                 :            :         static const Verb verbs[] = {
     484                 :            :                 { "help",          VERB_ANY, VERB_ANY, 0,            help        },
     485                 :            :                 { "status",        VERB_ANY, 1,        VERB_DEFAULT, verb_status },
     486                 :            :                 { "good",          VERB_ANY, 1,        0,            verb_set    },
     487                 :            :                 { "bad",           VERB_ANY, 1,        0,            verb_set    },
     488                 :            :                 { "indeterminate", VERB_ANY, 1,        0,            verb_set    },
     489                 :            :                 {}
     490                 :            :         };
     491                 :            : 
     492                 :            :         int r;
     493                 :            : 
     494                 :          0 :         log_parse_environment();
     495                 :          0 :         log_open();
     496                 :            : 
     497                 :          0 :         r = parse_argv(argc, argv);
     498         [ #  # ]:          0 :         if (r <= 0)
     499                 :          0 :                 return r;
     500                 :            : 
     501         [ #  # ]:          0 :         if (detect_container() > 0)
     502         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
     503                 :            :                                        "Marking a boot is not supported in containers.");
     504                 :            : 
     505         [ #  # ]:          0 :         if (!is_efi_boot())
     506         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
     507                 :            :                                        "Marking a boot is only supported on EFI systems.");
     508                 :            : 
     509                 :          0 :         return dispatch_verb(argc, argv, verbs, NULL);
     510                 :            : }
     511                 :            : 
     512                 :          0 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14