LCOV - code coverage report
Current view: top level - portable - portablectl.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 25 481 5.2 %
Date: 2019-08-23 13:36:53 Functions: 4 19 21.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 409 1.7 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <getopt.h>
       5                 :            : 
       6                 :            : #include "sd-bus.h"
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "bus-error.h"
      10                 :            : #include "bus-util.h"
      11                 :            : #include "def.h"
      12                 :            : #include "dirent-util.h"
      13                 :            : #include "env-file.h"
      14                 :            : #include "fd-util.h"
      15                 :            : #include "fileio.h"
      16                 :            : #include "format-table.h"
      17                 :            : #include "fs-util.h"
      18                 :            : #include "locale-util.h"
      19                 :            : #include "machine-image.h"
      20                 :            : #include "main-func.h"
      21                 :            : #include "pager.h"
      22                 :            : #include "parse-util.h"
      23                 :            : #include "path-util.h"
      24                 :            : #include "pretty-print.h"
      25                 :            : #include "spawn-polkit-agent.h"
      26                 :            : #include "string-util.h"
      27                 :            : #include "strv.h"
      28                 :            : #include "terminal-util.h"
      29                 :            : #include "verbs.h"
      30                 :            : 
      31                 :            : static PagerFlags arg_pager_flags = 0;
      32                 :            : static bool arg_legend = true;
      33                 :            : static bool arg_ask_password = true;
      34                 :            : static bool arg_quiet = false;
      35                 :            : static const char *arg_profile = "default";
      36                 :            : static const char* arg_copy_mode = NULL;
      37                 :            : static bool arg_runtime = false;
      38                 :            : static bool arg_reload = true;
      39                 :            : static bool arg_cat = false;
      40                 :            : static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
      41                 :            : static const char *arg_host = NULL;
      42                 :            : 
      43                 :          0 : static int determine_image(const char *image, bool permit_non_existing, char **ret) {
      44                 :            :         int r;
      45                 :            : 
      46                 :            :         /* If the specified name is a valid image name, we pass it as-is to portabled, which will search for it in the
      47                 :            :          * usual search directories. Otherwise we presume it's a path, and will normalize it on the client's side
      48                 :            :          * (among other things, to make the path independent of the client's working directory) before passing it
      49                 :            :          * over. */
      50                 :            : 
      51         [ #  # ]:          0 :         if (image_name_is_valid(image)) {
      52                 :            :                 char *c;
      53                 :            : 
      54   [ #  #  #  # ]:          0 :                 if (!arg_quiet && laccess(image, F_OK) >= 0)
      55         [ #  # ]:          0 :                         log_warning("Ambiguous invocation: current working directory contains file matching non-path argument '%s', ignoring. "
      56                 :            :                                     "Prefix argument with './' to force reference to file in current working directory.", image);
      57                 :            : 
      58                 :          0 :                 c = strdup(image);
      59         [ #  # ]:          0 :                 if (!c)
      60                 :          0 :                         return log_oom();
      61                 :            : 
      62                 :          0 :                 *ret = c;
      63                 :          0 :                 return 0;
      64                 :            :         }
      65                 :            : 
      66         [ #  # ]:          0 :         if (arg_transport != BUS_TRANSPORT_LOCAL)
      67         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
      68                 :            :                                        "Operations on images by path not supported when connecting to remote systems.");
      69                 :            : 
      70         [ #  # ]:          0 :         r = chase_symlinks(image, NULL, CHASE_TRAIL_SLASH | (permit_non_existing ? CHASE_NONEXISTENT : 0), ret);
      71         [ #  # ]:          0 :         if (r < 0)
      72         [ #  # ]:          0 :                 return log_error_errno(r, "Cannot normalize specified image path '%s': %m", image);
      73                 :            : 
      74                 :          0 :         return 0;
      75                 :            : }
      76                 :            : 
      77                 :          0 : static int extract_prefix(const char *path, char **ret) {
      78                 :          0 :         _cleanup_free_ char *name = NULL;
      79                 :            :         const char *bn, *underscore;
      80                 :            :         size_t m;
      81                 :            : 
      82                 :          0 :         bn = basename(path);
      83                 :            : 
      84                 :          0 :         underscore = strchr(bn, '_');
      85         [ #  # ]:          0 :         if (underscore)
      86                 :          0 :                 m = underscore - bn;
      87                 :            :         else {
      88                 :            :                 const char *e;
      89                 :            : 
      90                 :          0 :                 e = endswith(bn, ".raw");
      91         [ #  # ]:          0 :                 if (!e)
      92                 :          0 :                         e = strchr(bn, 0);
      93                 :            : 
      94                 :          0 :                 m = e - bn;
      95                 :            :         }
      96                 :            : 
      97                 :          0 :         name = strndup(bn, m);
      98         [ #  # ]:          0 :         if (!name)
      99                 :          0 :                 return -ENOMEM;
     100                 :            : 
     101                 :            :         /*  A slightly reduced version of what's permitted in unit names. With ':' and '\' are removed, as well as '_'
     102                 :            :          *  which we use as delimiter for the second part of the image string, which we ignore for now. */
     103         [ #  # ]:          0 :         if (!in_charset(name, DIGITS LETTERS "-."))
     104                 :          0 :                 return -EINVAL;
     105                 :            : 
     106         [ #  # ]:          0 :         if (!filename_is_valid(name))
     107                 :          0 :                 return -EINVAL;
     108                 :            : 
     109                 :          0 :         *ret = TAKE_PTR(name);
     110                 :            : 
     111                 :          0 :         return 0;
     112                 :            : }
     113                 :            : 
     114                 :          0 : static int determine_matches(const char *image, char **l, bool allow_any, char ***ret) {
     115                 :          0 :         _cleanup_strv_free_ char **k = NULL;
     116                 :            :         int r;
     117                 :            : 
     118                 :            :         /* Determine the matches to apply. If the list is empty we derive the match from the image name. If the list
     119                 :            :          * contains exactly the "-" we return a wildcard list (which is the empty list), but only if this is expressly
     120                 :            :          * permitted. */
     121                 :            : 
     122         [ #  # ]:          0 :         if (strv_isempty(l)) {
     123                 :            :                 char *prefix;
     124                 :            : 
     125                 :          0 :                 r = extract_prefix(image, &prefix);
     126         [ #  # ]:          0 :                 if (r < 0)
     127         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to extract prefix of image name '%s': %m", image);
     128                 :            : 
     129         [ #  # ]:          0 :                 if (!arg_quiet)
     130         [ #  # ]:          0 :                         log_info("(Matching unit files with prefix '%s'.)", prefix);
     131                 :            : 
     132                 :          0 :                 r = strv_consume(&k, prefix);
     133         [ #  # ]:          0 :                 if (r < 0)
     134                 :          0 :                         return log_oom();
     135                 :            : 
     136         [ #  # ]:          0 :         } else if (strv_equal(l, STRV_MAKE("-"))) {
     137                 :            : 
     138         [ #  # ]:          0 :                 if (!allow_any)
     139         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     140                 :            :                                                "Refusing all unit file match.");
     141                 :            : 
     142         [ #  # ]:          0 :                 if (!arg_quiet)
     143         [ #  # ]:          0 :                         log_info("(Matching all unit files.)");
     144                 :            :         } else {
     145                 :            : 
     146                 :          0 :                 k = strv_copy(l);
     147         [ #  # ]:          0 :                 if (!k)
     148                 :          0 :                         return log_oom();
     149                 :            : 
     150         [ #  # ]:          0 :                 if (!arg_quiet) {
     151         [ #  # ]:          0 :                         _cleanup_free_ char *joined = NULL;
     152                 :            : 
     153                 :          0 :                         joined = strv_join(k, "', '");
     154         [ #  # ]:          0 :                         if (!joined)
     155                 :          0 :                                 return log_oom();
     156                 :            : 
     157         [ #  # ]:          0 :                         log_info("(Matching unit files with prefixes '%s'.)", joined);
     158                 :            :                 }
     159                 :            :         }
     160                 :            : 
     161                 :          0 :         *ret = TAKE_PTR(k);
     162                 :            : 
     163                 :          0 :         return 0;
     164                 :            : }
     165                 :            : 
     166                 :          0 : static int acquire_bus(sd_bus **bus) {
     167                 :            :         int r;
     168                 :            : 
     169         [ #  # ]:          0 :         assert(bus);
     170                 :            : 
     171         [ #  # ]:          0 :         if (*bus)
     172                 :          0 :                 return 0;
     173                 :            : 
     174                 :          0 :         r = bus_connect_transport(arg_transport, arg_host, false, bus);
     175         [ #  # ]:          0 :         if (r < 0)
     176         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to bus: %m");
     177                 :            : 
     178                 :          0 :         (void) sd_bus_set_allow_interactive_authorization(*bus, arg_ask_password);
     179                 :            : 
     180                 :          0 :         return 0;
     181                 :            : }
     182                 :            : 
     183                 :          0 : static int maybe_reload(sd_bus **bus) {
     184                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     185                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     186                 :            :         int r;
     187                 :            : 
     188         [ #  # ]:          0 :         if (!arg_reload)
     189                 :          0 :                 return 0;
     190                 :            : 
     191                 :          0 :         r = acquire_bus(bus);
     192         [ #  # ]:          0 :         if (r < 0)
     193                 :          0 :                 return r;
     194                 :            : 
     195                 :          0 :         r = sd_bus_message_new_method_call(
     196                 :            :                         *bus,
     197                 :            :                         &m,
     198                 :            :                         "org.freedesktop.systemd1",
     199                 :            :                         "/org/freedesktop/systemd1",
     200                 :            :                         "org.freedesktop.systemd1.Manager",
     201                 :            :                         "Reload");
     202         [ #  # ]:          0 :         if (r < 0)
     203         [ #  # ]:          0 :                 return bus_log_create_error(r);
     204                 :            : 
     205                 :            :         /* Reloading the daemon may take long, hence set a longer timeout here */
     206                 :          0 :         r = sd_bus_call(*bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
     207         [ #  # ]:          0 :         if (r < 0)
     208         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
     209                 :            : 
     210                 :          0 :         return 0;
     211                 :            : }
     212                 :            : 
     213                 :          0 : static int inspect_image(int argc, char *argv[], void *userdata) {
     214                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
     215                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     216                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     217                 :          0 :         _cleanup_strv_free_ char **matches = NULL;
     218                 :          0 :         _cleanup_free_ char *image = NULL;
     219                 :          0 :         bool nl = false, header = false;
     220                 :            :         const void *data;
     221                 :            :         const char *path;
     222                 :            :         size_t sz;
     223                 :            :         int r;
     224                 :            : 
     225                 :          0 :         r = determine_image(argv[1], false, &image);
     226         [ #  # ]:          0 :         if (r < 0)
     227                 :          0 :                 return r;
     228                 :            : 
     229                 :          0 :         r = determine_matches(argv[1], argv + 2, true, &matches);
     230         [ #  # ]:          0 :         if (r < 0)
     231                 :          0 :                 return r;
     232                 :            : 
     233                 :          0 :         r = acquire_bus(&bus);
     234         [ #  # ]:          0 :         if (r < 0)
     235                 :          0 :                 return r;
     236                 :            : 
     237                 :          0 :         r = sd_bus_message_new_method_call(
     238                 :            :                                 bus,
     239                 :            :                                 &m,
     240                 :            :                                 "org.freedesktop.portable1",
     241                 :            :                                 "/org/freedesktop/portable1",
     242                 :            :                                 "org.freedesktop.portable1.Manager",
     243                 :            :                                 "GetImageMetadata");
     244         [ #  # ]:          0 :         if (r < 0)
     245         [ #  # ]:          0 :                 return bus_log_create_error(r);
     246                 :            : 
     247                 :          0 :         r = sd_bus_message_append(m, "s", image);
     248         [ #  # ]:          0 :         if (r < 0)
     249         [ #  # ]:          0 :                 return bus_log_create_error(r);
     250                 :            : 
     251                 :          0 :         r = sd_bus_message_append_strv(m, matches);
     252         [ #  # ]:          0 :         if (r < 0)
     253         [ #  # ]:          0 :                 return bus_log_create_error(r);
     254                 :            : 
     255                 :          0 :         r = sd_bus_call(bus, m, 0, &error, &reply);
     256         [ #  # ]:          0 :         if (r < 0)
     257         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to inspect image metadata: %s", bus_error_message(&error, r));
     258                 :            : 
     259                 :          0 :         r = sd_bus_message_read(reply, "s", &path);
     260         [ #  # ]:          0 :         if (r < 0)
     261         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     262                 :            : 
     263                 :          0 :         r = sd_bus_message_read_array(reply, 'y', &data, &sz);
     264         [ #  # ]:          0 :         if (r < 0)
     265         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     266                 :            : 
     267                 :          0 :         (void) pager_open(arg_pager_flags);
     268                 :            : 
     269         [ #  # ]:          0 :         if (arg_cat) {
     270                 :          0 :                 printf("%s-- OS Release: --%s\n", ansi_highlight(), ansi_normal());
     271                 :          0 :                 fwrite(data, sz, 1, stdout);
     272                 :          0 :                 fflush(stdout);
     273                 :          0 :                 nl = true;
     274                 :            :         } else {
     275   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *pretty_portable = NULL, *pretty_os = NULL;
     276         [ #  # ]:          0 :                 _cleanup_fclose_ FILE *f;
     277                 :            : 
     278                 :          0 :                 f = fmemopen_unlocked((void*) data, sz, "re");
     279         [ #  # ]:          0 :                 if (!f)
     280         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open /etc/os-release buffer: %m");
     281                 :            : 
     282                 :          0 :                 r = parse_env_file(f, "/etc/os-release",
     283                 :            :                                    "PORTABLE_PRETTY_NAME", &pretty_portable,
     284                 :            :                                    "PRETTY_NAME", &pretty_os);
     285         [ #  # ]:          0 :                 if (r < 0)
     286         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to parse /etc/os-release: %m");
     287                 :            : 
     288                 :          0 :                 printf("Image:\n\t%s\n"
     289                 :            :                        "Portable Service:\n\t%s\n"
     290                 :            :                        "Operating System:\n\t%s\n",
     291                 :            :                        path,
     292                 :            :                        strna(pretty_portable),
     293                 :            :                        strna(pretty_os));
     294                 :            :         }
     295                 :            : 
     296                 :          0 :         r = sd_bus_message_enter_container(reply, 'a', "{say}");
     297         [ #  # ]:          0 :         if (r < 0)
     298         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     299                 :            : 
     300                 :          0 :         for (;;) {
     301                 :            :                 const char *name;
     302                 :            : 
     303                 :          0 :                 r = sd_bus_message_enter_container(reply, 'e', "say");
     304         [ #  # ]:          0 :                 if (r < 0)
     305         [ #  # ]:          0 :                         return bus_log_parse_error(r);
     306         [ #  # ]:          0 :                 if (r == 0)
     307                 :          0 :                         break;
     308                 :            : 
     309                 :          0 :                 r = sd_bus_message_read(reply, "s", &name);
     310         [ #  # ]:          0 :                 if (r < 0)
     311         [ #  # ]:          0 :                         return bus_log_parse_error(r);
     312                 :            : 
     313                 :          0 :                 r = sd_bus_message_read_array(reply, 'y', &data, &sz);
     314         [ #  # ]:          0 :                 if (r < 0)
     315         [ #  # ]:          0 :                         return bus_log_parse_error(r);
     316                 :            : 
     317         [ #  # ]:          0 :                 if (arg_cat) {
     318         [ #  # ]:          0 :                         if (nl)
     319                 :          0 :                                 fputc('\n', stdout);
     320                 :            : 
     321                 :          0 :                         printf("%s-- Unit file: %s --%s\n", ansi_highlight(), name, ansi_normal());
     322                 :          0 :                         fwrite(data, sz, 1, stdout);
     323                 :          0 :                         fflush(stdout);
     324                 :          0 :                         nl = true;
     325                 :            :                 } else {
     326         [ #  # ]:          0 :                         if (!header) {
     327                 :          0 :                                 fputs("Unit files:\n", stdout);
     328                 :          0 :                                 header = true;
     329                 :            :                         }
     330                 :            : 
     331                 :          0 :                         fputc('\t', stdout);
     332                 :          0 :                         fputs(name, stdout);
     333                 :          0 :                         fputc('\n', stdout);
     334                 :            :                 }
     335                 :            : 
     336                 :          0 :                 r = sd_bus_message_exit_container(reply);
     337         [ #  # ]:          0 :                 if (r < 0)
     338         [ #  # ]:          0 :                         return bus_log_parse_error(r);
     339                 :            :         }
     340                 :            : 
     341                 :          0 :         r = sd_bus_message_exit_container(reply);
     342         [ #  # ]:          0 :         if (r < 0)
     343         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     344                 :            : 
     345                 :          0 :         return 0;
     346                 :            : }
     347                 :            : 
     348                 :          0 : static int print_changes(sd_bus_message *m) {
     349                 :            :         int r;
     350                 :            : 
     351         [ #  # ]:          0 :         if (arg_quiet)
     352                 :          0 :                 return 0;
     353                 :            : 
     354                 :          0 :         r = sd_bus_message_enter_container(m, 'a', "(sss)");
     355         [ #  # ]:          0 :         if (r < 0)
     356         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     357                 :            : 
     358                 :          0 :         for (;;) {
     359                 :            :                 const char *type, *path, *source;
     360                 :            : 
     361                 :          0 :                 r = sd_bus_message_read(m, "(sss)", &type, &path, &source);
     362         [ #  # ]:          0 :                 if (r < 0)
     363         [ #  # ]:          0 :                         return bus_log_parse_error(r);
     364         [ #  # ]:          0 :                 if (r == 0)
     365                 :          0 :                         break;
     366                 :            : 
     367         [ #  # ]:          0 :                 if (streq(type, "symlink"))
     368         [ #  # ]:          0 :                         log_info("Created symlink %s %s %s.", path, special_glyph(SPECIAL_GLYPH_ARROW), source);
     369         [ #  # ]:          0 :                 else if (streq(type, "copy")) {
     370         [ #  # ]:          0 :                         if (isempty(source))
     371         [ #  # ]:          0 :                                 log_info("Copied %s.", path);
     372                 :            :                         else
     373         [ #  # ]:          0 :                                 log_info("Copied %s %s %s.", source, special_glyph(SPECIAL_GLYPH_ARROW), path);
     374         [ #  # ]:          0 :                 } else if (streq(type, "unlink"))
     375         [ #  # ]:          0 :                         log_info("Removed %s.", path);
     376         [ #  # ]:          0 :                 else if (streq(type, "write"))
     377         [ #  # ]:          0 :                         log_info("Written %s.", path);
     378         [ #  # ]:          0 :                 else if (streq(type, "mkdir"))
     379         [ #  # ]:          0 :                         log_info("Created directory %s.", path);
     380                 :            :                 else
     381         [ #  # ]:          0 :                         log_error("Unexpected change: %s/%s/%s", type, path, source);
     382                 :            :         }
     383                 :            : 
     384                 :          0 :         r = sd_bus_message_exit_container(m);
     385         [ #  # ]:          0 :         if (r < 0)
     386                 :          0 :                 return r;
     387                 :            : 
     388                 :          0 :         return 0;
     389                 :            : }
     390                 :            : 
     391                 :          0 : static int attach_image(int argc, char *argv[], void *userdata) {
     392                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
     393                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     394                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     395                 :          0 :         _cleanup_strv_free_ char **matches = NULL;
     396                 :          0 :         _cleanup_free_ char *image = NULL;
     397                 :            :         int r;
     398                 :            : 
     399                 :          0 :         r = determine_image(argv[1], false, &image);
     400         [ #  # ]:          0 :         if (r < 0)
     401                 :          0 :                 return r;
     402                 :            : 
     403                 :          0 :         r = determine_matches(argv[1], argv + 2, false, &matches);
     404         [ #  # ]:          0 :         if (r < 0)
     405                 :          0 :                 return r;
     406                 :            : 
     407                 :          0 :         r = acquire_bus(&bus);
     408         [ #  # ]:          0 :         if (r < 0)
     409                 :          0 :                 return r;
     410                 :            : 
     411                 :          0 :         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     412                 :            : 
     413                 :          0 :         r = sd_bus_message_new_method_call(
     414                 :            :                                 bus,
     415                 :            :                                 &m,
     416                 :            :                                 "org.freedesktop.portable1",
     417                 :            :                                 "/org/freedesktop/portable1",
     418                 :            :                                 "org.freedesktop.portable1.Manager",
     419                 :            :                                 "AttachImage");
     420         [ #  # ]:          0 :         if (r < 0)
     421         [ #  # ]:          0 :                 return bus_log_create_error(r);
     422                 :            : 
     423                 :          0 :         r = sd_bus_message_append(m, "s", image);
     424         [ #  # ]:          0 :         if (r < 0)
     425         [ #  # ]:          0 :                 return bus_log_create_error(r);
     426                 :            : 
     427                 :          0 :         r = sd_bus_message_append_strv(m, matches);
     428         [ #  # ]:          0 :         if (r < 0)
     429         [ #  # ]:          0 :                 return bus_log_create_error(r);
     430                 :            : 
     431                 :          0 :         r = sd_bus_message_append(m, "sbs", arg_profile, arg_runtime, arg_copy_mode);
     432         [ #  # ]:          0 :         if (r < 0)
     433         [ #  # ]:          0 :                 return bus_log_create_error(r);
     434                 :            : 
     435                 :          0 :         r = sd_bus_call(bus, m, 0, &error, &reply);
     436         [ #  # ]:          0 :         if (r < 0)
     437         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to attach image: %s", bus_error_message(&error, r));
     438                 :            : 
     439                 :          0 :         (void) maybe_reload(&bus);
     440                 :            : 
     441                 :          0 :         print_changes(reply);
     442                 :          0 :         return 0;
     443                 :            : }
     444                 :            : 
     445                 :          0 : static int detach_image(int argc, char *argv[], void *userdata) {
     446                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     447                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     448                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     449                 :          0 :         _cleanup_free_ char *image = NULL;
     450                 :            :         int r;
     451                 :            : 
     452                 :          0 :         r = determine_image(argv[1], true, &image);
     453         [ #  # ]:          0 :         if (r < 0)
     454                 :          0 :                 return r;
     455                 :            : 
     456                 :          0 :         r = acquire_bus(&bus);
     457         [ #  # ]:          0 :         if (r < 0)
     458                 :          0 :                 return r;
     459                 :            : 
     460                 :          0 :         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     461                 :            : 
     462                 :          0 :         r = sd_bus_call_method(
     463                 :            :                         bus,
     464                 :            :                         "org.freedesktop.portable1",
     465                 :            :                         "/org/freedesktop/portable1",
     466                 :            :                         "org.freedesktop.portable1.Manager",
     467                 :            :                         "DetachImage",
     468                 :            :                         &error,
     469                 :            :                         &reply,
     470                 :            :                         "sb", image, arg_runtime);
     471         [ #  # ]:          0 :         if (r < 0)
     472         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to detach image: %s", bus_error_message(&error, r));
     473                 :            : 
     474                 :          0 :         (void) maybe_reload(&bus);
     475                 :            : 
     476                 :          0 :         print_changes(reply);
     477                 :          0 :         return 0;
     478                 :            : }
     479                 :            : 
     480                 :          0 : static int list_images(int argc, char *argv[], void *userdata) {
     481                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     482                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     483                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     484                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
     485                 :            :         int r;
     486                 :            : 
     487                 :          0 :         r = acquire_bus(&bus);
     488         [ #  # ]:          0 :         if (r < 0)
     489                 :          0 :                 return r;
     490                 :            : 
     491                 :          0 :         r = sd_bus_call_method(
     492                 :            :                         bus,
     493                 :            :                         "org.freedesktop.portable1",
     494                 :            :                         "/org/freedesktop/portable1",
     495                 :            :                         "org.freedesktop.portable1.Manager",
     496                 :            :                         "ListImages",
     497                 :            :                         &error,
     498                 :            :                         &reply,
     499                 :            :                         NULL);
     500         [ #  # ]:          0 :         if (r < 0)
     501         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r));
     502                 :            : 
     503                 :          0 :         table = table_new("name", "type", "ro", "crtime", "mtime", "usage", "state");
     504         [ #  # ]:          0 :         if (!table)
     505                 :          0 :                 return log_oom();
     506                 :            : 
     507                 :          0 :         r = sd_bus_message_enter_container(reply, 'a', "(ssbtttso)");
     508         [ #  # ]:          0 :         if (r < 0)
     509         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     510                 :            : 
     511                 :          0 :         for (;;) {
     512                 :            :                 const char *name, *type, *state;
     513                 :            :                 uint64_t crtime, mtime, usage;
     514                 :            :                 TableCell *cell;
     515                 :            :                 bool ro_bool;
     516                 :            :                 int ro_int;
     517                 :            : 
     518                 :          0 :                 r = sd_bus_message_read(reply, "(ssbtttso)", &name, &type, &ro_int, &crtime, &mtime, &usage, &state, NULL);
     519         [ #  # ]:          0 :                 if (r < 0)
     520         [ #  # ]:          0 :                         return bus_log_parse_error(r);
     521         [ #  # ]:          0 :                 if (r == 0)
     522                 :          0 :                         break;
     523                 :            : 
     524                 :          0 :                 r = table_add_many(table,
     525                 :            :                                    TABLE_STRING, name,
     526                 :            :                                    TABLE_STRING, type);
     527         [ #  # ]:          0 :                 if (r < 0)
     528         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     529                 :            : 
     530                 :          0 :                 ro_bool = ro_int;
     531                 :          0 :                 r = table_add_cell(table, &cell, TABLE_BOOLEAN, &ro_bool);
     532         [ #  # ]:          0 :                 if (r < 0)
     533         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     534                 :            : 
     535         [ #  # ]:          0 :                 if (ro_bool) {
     536                 :          0 :                         r = table_set_color(table, cell, ansi_highlight_red());
     537         [ #  # ]:          0 :                         if (r < 0)
     538         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to set table cell color: %m");
     539                 :            :                 }
     540                 :            : 
     541                 :          0 :                 r = table_add_many(table,
     542                 :            :                                    TABLE_TIMESTAMP, crtime,
     543                 :            :                                    TABLE_TIMESTAMP, mtime,
     544                 :            :                                    TABLE_SIZE, usage);
     545         [ #  # ]:          0 :                 if (r < 0)
     546         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     547                 :            : 
     548                 :          0 :                 r = table_add_cell(table, &cell, TABLE_STRING, state);
     549         [ #  # ]:          0 :                 if (r < 0)
     550         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     551                 :            : 
     552         [ #  # ]:          0 :                 if (!streq(state, "detached")) {
     553                 :          0 :                         r = table_set_color(table, cell, ansi_highlight_green());
     554         [ #  # ]:          0 :                         if (r < 0)
     555         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to set table cell color: %m");
     556                 :            :                 }
     557                 :            :         }
     558                 :            : 
     559                 :          0 :         r = sd_bus_message_exit_container(reply);
     560         [ #  # ]:          0 :         if (r < 0)
     561         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     562                 :            : 
     563         [ #  # ]:          0 :         if (table_get_rows(table) > 1) {
     564                 :          0 :                 r = table_set_sort(table, (size_t) 0, (size_t) -1);
     565         [ #  # ]:          0 :                 if (r < 0)
     566         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to sort table: %m");
     567                 :            : 
     568                 :          0 :                 table_set_header(table, arg_legend);
     569                 :            : 
     570                 :          0 :                 r = table_print(table, NULL);
     571         [ #  # ]:          0 :                 if (r < 0)
     572         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to show table: %m");
     573                 :            :         }
     574                 :            : 
     575         [ #  # ]:          0 :         if (arg_legend) {
     576         [ #  # ]:          0 :                 if (table_get_rows(table) > 1)
     577                 :          0 :                         printf("\n%zu images listed.\n", table_get_rows(table) - 1);
     578                 :            :                 else
     579                 :          0 :                         printf("No images.\n");
     580                 :            :         }
     581                 :            : 
     582                 :          0 :         return 0;
     583                 :            : }
     584                 :            : 
     585                 :          0 : static int remove_image(int argc, char *argv[], void *userdata) {
     586                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     587                 :            :         int r, i;
     588                 :            : 
     589                 :          0 :         r = acquire_bus(&bus);
     590         [ #  # ]:          0 :         if (r < 0)
     591                 :          0 :                 return r;
     592                 :            : 
     593                 :          0 :         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     594                 :            : 
     595         [ #  # ]:          0 :         for (i = 1; i < argc; i++) {
     596         [ #  # ]:          0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     597         [ #  # ]:          0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     598                 :            : 
     599                 :          0 :                 r = sd_bus_message_new_method_call(
     600                 :            :                                 bus,
     601                 :            :                                 &m,
     602                 :            :                                 "org.freedesktop.portable1",
     603                 :            :                                 "/org/freedesktop/portable1",
     604                 :            :                                 "org.freedesktop.portable1.Manager",
     605                 :            :                                 "RemoveImage");
     606         [ #  # ]:          0 :                 if (r < 0)
     607         [ #  # ]:          0 :                         return bus_log_create_error(r);
     608                 :            : 
     609                 :          0 :                 r = sd_bus_message_append(m, "s", argv[i]);
     610         [ #  # ]:          0 :                 if (r < 0)
     611         [ #  # ]:          0 :                         return bus_log_create_error(r);
     612                 :            : 
     613                 :            :                 /* This is a slow operation, hence turn off any method call timeouts */
     614                 :          0 :                 r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
     615         [ #  # ]:          0 :                 if (r < 0)
     616         [ #  # ]:          0 :                         return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
     617                 :            :         }
     618                 :            : 
     619                 :          0 :         return 0;
     620                 :            : }
     621                 :            : 
     622                 :          0 : static int read_only_image(int argc, char *argv[], void *userdata) {
     623                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     624                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     625                 :          0 :         int b = true, r;
     626                 :            : 
     627         [ #  # ]:          0 :         if (argc > 2) {
     628                 :          0 :                 b = parse_boolean(argv[2]);
     629         [ #  # ]:          0 :                 if (b < 0)
     630         [ #  # ]:          0 :                         return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]);
     631                 :            :         }
     632                 :            : 
     633                 :          0 :         r = acquire_bus(&bus);
     634         [ #  # ]:          0 :         if (r < 0)
     635                 :          0 :                 return r;
     636                 :            : 
     637                 :          0 :         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     638                 :            : 
     639                 :          0 :         r = sd_bus_call_method(
     640                 :            :                         bus,
     641                 :            :                         "org.freedesktop.portable1",
     642                 :            :                         "/org/freedesktop/portable1",
     643                 :            :                         "org.freedesktop.portable1.Manager",
     644                 :            :                         "MarkImageReadOnly",
     645                 :            :                         &error,
     646                 :            :                         NULL,
     647                 :          0 :                         "sb", argv[1], b);
     648         [ #  # ]:          0 :         if (r < 0)
     649         [ #  # ]:          0 :                 return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, r));
     650                 :            : 
     651                 :          0 :         return 0;
     652                 :            : }
     653                 :            : 
     654                 :          0 : static int set_limit(int argc, char *argv[], void *userdata) {
     655                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     656                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     657                 :            :         uint64_t limit;
     658                 :            :         int r;
     659                 :            : 
     660                 :          0 :         r = acquire_bus(&bus);
     661         [ #  # ]:          0 :         if (r < 0)
     662                 :          0 :                 return r;
     663                 :            : 
     664                 :          0 :         (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     665                 :            : 
     666         [ #  # ]:          0 :         if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
     667                 :          0 :                 limit = (uint64_t) -1;
     668                 :            :         else {
     669                 :          0 :                 r = parse_size(argv[argc-1], 1024, &limit);
     670         [ #  # ]:          0 :                 if (r < 0)
     671         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to parse size: %s", argv[argc-1]);
     672                 :            :         }
     673                 :            : 
     674         [ #  # ]:          0 :         if (argc > 2)
     675                 :            :                 /* With two arguments changes the quota limit of the specified image */
     676                 :          0 :                 r = sd_bus_call_method(
     677                 :            :                                 bus,
     678                 :            :                                 "org.freedesktop.portable1",
     679                 :            :                                 "/org/freedesktop/portable1",
     680                 :            :                                 "org.freedesktop.portable1.Manager",
     681                 :            :                                 "SetImageLimit",
     682                 :            :                                 &error,
     683                 :            :                                 NULL,
     684                 :          0 :                                 "st", argv[1], limit);
     685                 :            :         else
     686                 :            :                 /* With one argument changes the pool quota limit */
     687                 :          0 :                 r = sd_bus_call_method(
     688                 :            :                                 bus,
     689                 :            :                                 "org.freedesktop.portable1",
     690                 :            :                                 "/org/freedesktop/portable1",
     691                 :            :                                 "org.freedesktop.portable1.Manager",
     692                 :            :                                 "SetPoolLimit",
     693                 :            :                                 &error,
     694                 :            :                                 NULL,
     695                 :            :                                 "t", limit);
     696                 :            : 
     697         [ #  # ]:          0 :         if (r < 0)
     698         [ #  # ]:          0 :                 return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
     699                 :            : 
     700                 :          0 :         return 0;
     701                 :            : }
     702                 :            : 
     703                 :          0 : static int is_image_attached(int argc, char *argv[], void *userdata) {
     704                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     705                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     706                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     707                 :          0 :         _cleanup_free_ char *image = NULL;
     708                 :            :         const char *state;
     709                 :            :         int r;
     710                 :            : 
     711                 :          0 :         r = determine_image(argv[1], true, &image);
     712         [ #  # ]:          0 :         if (r < 0)
     713                 :          0 :                 return r;
     714                 :            : 
     715                 :          0 :         r = acquire_bus(&bus);
     716         [ #  # ]:          0 :         if (r < 0)
     717                 :          0 :                 return r;
     718                 :            : 
     719                 :          0 :         r = sd_bus_call_method(
     720                 :            :                         bus,
     721                 :            :                         "org.freedesktop.portable1",
     722                 :            :                         "/org/freedesktop/portable1",
     723                 :            :                         "org.freedesktop.portable1.Manager",
     724                 :            :                         "GetImageState",
     725                 :            :                         &error,
     726                 :            :                         &reply,
     727                 :            :                         "s", image);
     728         [ #  # ]:          0 :         if (r < 0)
     729         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get image state: %s", bus_error_message(&error, r));
     730                 :            : 
     731                 :          0 :         r = sd_bus_message_read(reply, "s", &state);
     732         [ #  # ]:          0 :         if (r < 0)
     733                 :          0 :                 return r;
     734                 :            : 
     735         [ #  # ]:          0 :         if (!arg_quiet)
     736                 :          0 :                 puts(state);
     737                 :            : 
     738                 :          0 :         return streq(state, "detached");
     739                 :            : }
     740                 :            : 
     741                 :          0 : static int dump_profiles(void) {
     742                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     743                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     744                 :          0 :         _cleanup_strv_free_ char **l = NULL;
     745                 :            :         char **i;
     746                 :            :         int r;
     747                 :            : 
     748                 :          0 :         r = acquire_bus(&bus);
     749         [ #  # ]:          0 :         if (r < 0)
     750                 :          0 :                 return r;
     751                 :            : 
     752                 :          0 :         r = sd_bus_get_property_strv(
     753                 :            :                         bus,
     754                 :            :                         "org.freedesktop.portable1",
     755                 :            :                         "/org/freedesktop/portable1",
     756                 :            :                         "org.freedesktop.portable1.Manager",
     757                 :            :                         "Profiles",
     758                 :            :                         &error,
     759                 :            :                         &l);
     760         [ #  # ]:          0 :         if (r < 0)
     761         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to acquire list of profiles: %s", bus_error_message(&error, r));
     762                 :            : 
     763         [ #  # ]:          0 :         if (arg_legend)
     764         [ #  # ]:          0 :                 log_info("Available unit profiles:");
     765                 :            : 
     766   [ #  #  #  # ]:          0 :         STRV_FOREACH(i, l) {
     767                 :          0 :                 fputs(*i, stdout);
     768                 :          0 :                 fputc('\n', stdout);
     769                 :            :         }
     770                 :            : 
     771                 :          0 :         return 0;
     772                 :            : }
     773                 :            : 
     774                 :         12 : static int help(int argc, char *argv[], void *userdata) {
     775                 :         12 :         _cleanup_free_ char *link = NULL;
     776                 :            :         int r;
     777                 :            : 
     778                 :         12 :         (void) pager_open(arg_pager_flags);
     779                 :            : 
     780                 :         12 :         r = terminal_urlify_man("portablectl", "1", &link);
     781         [ -  + ]:         12 :         if (r < 0)
     782                 :          0 :                 return log_oom();
     783                 :            : 
     784                 :         12 :         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
     785                 :            :                "Attach or detach portable services from the local system.\n\n"
     786                 :            :                "  -h --help                   Show this help\n"
     787                 :            :                "     --version                Show package version\n"
     788                 :            :                "     --no-pager               Do not pipe output into a pager\n"
     789                 :            :                "     --no-legend              Do not show the headers and footers\n"
     790                 :            :                "     --no-ask-password        Do not ask for system passwords\n"
     791                 :            :                "  -H --host=[USER@]HOST       Operate on remote host\n"
     792                 :            :                "  -M --machine=CONTAINER      Operate on local container\n"
     793                 :            :                "  -q --quiet                  Suppress informational messages\n"
     794                 :            :                "  -p --profile=PROFILE        Pick security profile for portable service\n"
     795                 :            :                "     --copy=copy|auto|symlink Prefer copying or symlinks if possible\n"
     796                 :            :                "     --runtime                Attach portable service until next reboot only\n"
     797                 :            :                "     --no-reload              Don't reload the system and service manager\n"
     798                 :            :                "     --cat                    When inspecting include unit and os-release file\n"
     799                 :            :                "                              contents\n\n"
     800                 :            :                "Commands:\n"
     801                 :            :                "  list                        List available portable service images\n"
     802                 :            :                "  attach NAME|PATH [PREFIX...]\n"
     803                 :            :                "                              Attach the specified portable service image\n"
     804                 :            :                "  detach NAME|PATH            Detach the specified portable service image\n"
     805                 :            :                "  inspect NAME|PATH [PREFIX...]\n"
     806                 :            :                "                              Show details of specified portable service image\n"
     807                 :            :                "  is-attached NAME|PATH       Query if portable service image is attached\n"
     808                 :            :                "  read-only NAME|PATH [BOOL]  Mark or unmark portable service image read-only\n"
     809                 :            :                "  remove NAME|PATH...         Remove a portable service image\n"
     810                 :            :                "  set-limit [NAME|PATH]       Set image or pool size limit (disk quota)\n"
     811                 :            :                "\nSee the %s for details.\n"
     812                 :            :                , program_invocation_short_name
     813                 :            :                , link
     814                 :            :         );
     815                 :            : 
     816                 :         12 :         return 0;
     817                 :            : }
     818                 :            : 
     819                 :         16 : static int parse_argv(int argc, char *argv[]) {
     820                 :            : 
     821                 :            :         enum {
     822                 :            :                 ARG_VERSION = 0x100,
     823                 :            :                 ARG_NO_PAGER,
     824                 :            :                 ARG_NO_LEGEND,
     825                 :            :                 ARG_NO_ASK_PASSWORD,
     826                 :            :                 ARG_COPY,
     827                 :            :                 ARG_RUNTIME,
     828                 :            :                 ARG_NO_RELOAD,
     829                 :            :                 ARG_CAT,
     830                 :            :         };
     831                 :            : 
     832                 :            :         static const struct option options[] = {
     833                 :            :                 { "help",            no_argument,       NULL, 'h'                 },
     834                 :            :                 { "version",         no_argument,       NULL, ARG_VERSION         },
     835                 :            :                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
     836                 :            :                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
     837                 :            :                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
     838                 :            :                 { "host",            required_argument, NULL, 'H'                 },
     839                 :            :                 { "machine",         required_argument, NULL, 'M'                 },
     840                 :            :                 { "quiet",           no_argument,       NULL, 'q'                 },
     841                 :            :                 { "profile",         required_argument, NULL, 'p'                 },
     842                 :            :                 { "copy",            required_argument, NULL, ARG_COPY            },
     843                 :            :                 { "runtime",         no_argument,       NULL, ARG_RUNTIME         },
     844                 :            :                 { "no-reload",       no_argument,       NULL, ARG_NO_RELOAD       },
     845                 :            :                 { "cat",             no_argument,       NULL, ARG_CAT             },
     846                 :            :                 {}
     847                 :            :         };
     848                 :            : 
     849         [ -  + ]:         16 :         assert(argc >= 0);
     850         [ -  + ]:         16 :         assert(argv);
     851                 :            : 
     852                 :          0 :         for (;;) {
     853                 :            :                 int c;
     854                 :            : 
     855                 :         16 :                 c = getopt_long(argc, argv, "hH:M:qp:", options, NULL);
     856         [ -  + ]:         16 :                 if (c < 0)
     857                 :          0 :                         break;
     858                 :            : 
     859   [ +  -  -  -  :         16 :                 switch (c) {
          -  -  -  -  -  
          -  -  -  -  +  
                      - ]
     860                 :            : 
     861                 :         12 :                 case 'h':
     862                 :         12 :                         return help(0, NULL, NULL);
     863                 :            : 
     864                 :          0 :                 case ARG_VERSION:
     865                 :          0 :                         return version();
     866                 :            : 
     867                 :          0 :                 case ARG_NO_PAGER:
     868                 :          0 :                         arg_pager_flags |= PAGER_DISABLE;
     869                 :          0 :                         break;
     870                 :            : 
     871                 :          0 :                 case ARG_NO_LEGEND:
     872                 :          0 :                         arg_legend = false;
     873                 :          0 :                         break;
     874                 :            : 
     875                 :          0 :                 case ARG_NO_ASK_PASSWORD:
     876                 :          0 :                         arg_ask_password = false;
     877                 :          0 :                         break;
     878                 :            : 
     879                 :          0 :                 case 'H':
     880                 :          0 :                         arg_transport = BUS_TRANSPORT_REMOTE;
     881                 :          0 :                         arg_host = optarg;
     882                 :          0 :                         break;
     883                 :            : 
     884                 :          0 :                 case 'M':
     885                 :          0 :                         arg_transport = BUS_TRANSPORT_MACHINE;
     886                 :          0 :                         arg_host = optarg;
     887                 :          0 :                         break;
     888                 :            : 
     889                 :          0 :                 case 'q':
     890                 :          0 :                         arg_quiet = true;
     891                 :          0 :                         break;
     892                 :            : 
     893                 :          0 :                 case 'p':
     894         [ #  # ]:          0 :                         if (streq(optarg, "help"))
     895                 :          0 :                                 return dump_profiles();
     896                 :            : 
     897         [ #  # ]:          0 :                         if (!filename_is_valid(optarg))
     898         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     899                 :            :                                                        "Unit profile name not valid: %s", optarg);
     900                 :            : 
     901                 :          0 :                         arg_profile = optarg;
     902                 :          0 :                         break;
     903                 :            : 
     904                 :          0 :                 case ARG_COPY:
     905         [ #  # ]:          0 :                         if (streq(optarg, "auto"))
     906                 :          0 :                                 arg_copy_mode = NULL;
     907         [ #  # ]:          0 :                         else if (STR_IN_SET(optarg, "copy", "symlink"))
     908                 :          0 :                                 arg_copy_mode = optarg;
     909         [ #  # ]:          0 :                         else if (streq(optarg, "help")) {
     910                 :          0 :                                 puts("auto\n"
     911                 :            :                                      "copy\n"
     912                 :            :                                      "symlink");
     913                 :          0 :                                 return 0;
     914                 :            :                         } else
     915         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     916                 :            :                                                        "Failed to parse --copy= argument: %s", optarg);
     917                 :            : 
     918                 :          0 :                         break;
     919                 :            : 
     920                 :          0 :                 case ARG_RUNTIME:
     921                 :          0 :                         arg_runtime = true;
     922                 :          0 :                         break;
     923                 :            : 
     924                 :          0 :                 case ARG_NO_RELOAD:
     925                 :          0 :                         arg_reload = false;
     926                 :          0 :                         break;
     927                 :            : 
     928                 :          0 :                 case ARG_CAT:
     929                 :          0 :                         arg_cat = true;
     930                 :          0 :                         break;
     931                 :            : 
     932                 :          4 :                 case '?':
     933                 :          4 :                         return -EINVAL;
     934                 :            : 
     935                 :          0 :                 default:
     936                 :          0 :                         assert_not_reached("Unhandled option");
     937                 :            :                 }
     938                 :            :         }
     939                 :            : 
     940                 :          0 :         return 1;
     941                 :            : }
     942                 :            : 
     943                 :         16 : static int run(int argc, char *argv[]) {
     944                 :            :         static const Verb verbs[] = {
     945                 :            :                 { "help",        VERB_ANY, VERB_ANY, 0,            help              },
     946                 :            :                 { "list",        VERB_ANY, 1,        VERB_DEFAULT, list_images       },
     947                 :            :                 { "attach",      2,        VERB_ANY, 0,            attach_image      },
     948                 :            :                 { "detach",      2,        2,        0,            detach_image      },
     949                 :            :                 { "inspect",     2,        VERB_ANY, 0,            inspect_image     },
     950                 :            :                 { "is-attached", 2,        2,        0,            is_image_attached },
     951                 :            :                 { "read-only",   2,        3,        0,            read_only_image   },
     952                 :            :                 { "remove",      2,        VERB_ANY, 0,            remove_image      },
     953                 :            :                 { "set-limit",   3,        3,        0,            set_limit         },
     954                 :            :                 {}
     955                 :            :         };
     956                 :            : 
     957                 :            :         int r;
     958                 :            : 
     959                 :         16 :         log_show_color(true);
     960                 :         16 :         log_parse_environment();
     961                 :         16 :         log_open();
     962                 :            : 
     963                 :         16 :         r = parse_argv(argc, argv);
     964         [ +  - ]:         16 :         if (r <= 0)
     965                 :         16 :                 return r;
     966                 :            : 
     967                 :          0 :         return dispatch_verb(argc, argv, verbs, NULL);
     968                 :            : }
     969                 :            : 
     970                 :         16 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14