LCOV - code coverage report
Current view: top level - analyze - analyze.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 30 1229 2.4 %
Date: 2019-08-23 13:36:53 Functions: 6 62 9.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8 1042 0.8 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2013 Simon Peeters
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <getopt.h>
       7                 :            : #include <inttypes.h>
       8                 :            : #include <locale.h>
       9                 :            : #include <stdio.h>
      10                 :            : #include <stdlib.h>
      11                 :            : #include <unistd.h>
      12                 :            : 
      13                 :            : #include "sd-bus.h"
      14                 :            : 
      15                 :            : #include "alloc-util.h"
      16                 :            : #include "analyze-condition.h"
      17                 :            : #include "analyze-security.h"
      18                 :            : #include "analyze-verify.h"
      19                 :            : #include "build.h"
      20                 :            : #include "bus-error.h"
      21                 :            : #include "bus-unit-util.h"
      22                 :            : #include "bus-util.h"
      23                 :            : #include "calendarspec.h"
      24                 :            : #include "conf-files.h"
      25                 :            : #include "copy.h"
      26                 :            : #include "def.h"
      27                 :            : #include "exit-status.h"
      28                 :            : #include "fd-util.h"
      29                 :            : #include "fileio.h"
      30                 :            : #include "format-table.h"
      31                 :            : #include "glob-util.h"
      32                 :            : #include "hashmap.h"
      33                 :            : #include "locale-util.h"
      34                 :            : #include "log.h"
      35                 :            : #include "main-func.h"
      36                 :            : #include "nulstr-util.h"
      37                 :            : #include "pager.h"
      38                 :            : #include "parse-util.h"
      39                 :            : #include "path-util.h"
      40                 :            : #include "pretty-print.h"
      41                 :            : #if HAVE_SECCOMP
      42                 :            : #  include "seccomp-util.h"
      43                 :            : #endif
      44                 :            : #include "sort-util.h"
      45                 :            : #include "special.h"
      46                 :            : #include "strv.h"
      47                 :            : #include "strxcpyx.h"
      48                 :            : #include "terminal-util.h"
      49                 :            : #include "time-util.h"
      50                 :            : #include "unit-name.h"
      51                 :            : #include "util.h"
      52                 :            : #include "verbs.h"
      53                 :            : 
      54                 :            : #define SCALE_X (0.1 / 1000.0) /* pixels per us */
      55                 :            : #define SCALE_Y (20.0)
      56                 :            : 
      57                 :            : #define svg(...) printf(__VA_ARGS__)
      58                 :            : 
      59                 :            : #define svg_bar(class, x1, x2, y)                                       \
      60                 :            :         svg("  <rect class=\"%s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", \
      61                 :            :             (class),                                                    \
      62                 :            :             SCALE_X * (x1), SCALE_Y * (y),                              \
      63                 :            :             SCALE_X * ((x2) - (x1)), SCALE_Y - 1.0)
      64                 :            : 
      65                 :            : #define svg_text(b, x, y, format, ...)                                  \
      66                 :            :         do {                                                            \
      67                 :            :                 svg("  <text class=\"%s\" x=\"%.03f\" y=\"%.03f\">", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \
      68                 :            :                 svg(format, ## __VA_ARGS__);                            \
      69                 :            :                 svg("</text>\n");                                       \
      70                 :            :         } while (false)
      71                 :            : 
      72                 :            : static enum dot {
      73                 :            :         DEP_ALL,
      74                 :            :         DEP_ORDER,
      75                 :            :         DEP_REQUIRE
      76                 :            : } arg_dot = DEP_ALL;
      77                 :            : static char **arg_dot_from_patterns = NULL;
      78                 :            : static char **arg_dot_to_patterns = NULL;
      79                 :            : static usec_t arg_fuzz = 0;
      80                 :            : static PagerFlags arg_pager_flags = 0;
      81                 :            : static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
      82                 :            : static const char *arg_host = NULL;
      83                 :            : static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
      84                 :            : static bool arg_man = true;
      85                 :            : static bool arg_generators = false;
      86                 :            : static const char *arg_root = NULL;
      87                 :            : static unsigned arg_iterations = 1;
      88                 :            : 
      89                 :         16 : STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
      90                 :         16 : STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
      91                 :            : 
      92                 :            : struct boot_times {
      93                 :            :         usec_t firmware_time;
      94                 :            :         usec_t loader_time;
      95                 :            :         usec_t kernel_time;
      96                 :            :         usec_t kernel_done_time;
      97                 :            :         usec_t initrd_time;
      98                 :            :         usec_t userspace_time;
      99                 :            :         usec_t finish_time;
     100                 :            :         usec_t security_start_time;
     101                 :            :         usec_t security_finish_time;
     102                 :            :         usec_t generators_start_time;
     103                 :            :         usec_t generators_finish_time;
     104                 :            :         usec_t unitsload_start_time;
     105                 :            :         usec_t unitsload_finish_time;
     106                 :            :         usec_t initrd_security_start_time;
     107                 :            :         usec_t initrd_security_finish_time;
     108                 :            :         usec_t initrd_generators_start_time;
     109                 :            :         usec_t initrd_generators_finish_time;
     110                 :            :         usec_t initrd_unitsload_start_time;
     111                 :            :         usec_t initrd_unitsload_finish_time;
     112                 :            : 
     113                 :            :         /*
     114                 :            :          * If we're analyzing the user instance, all timestamps will be offset
     115                 :            :          * by its own start-up timestamp, which may be arbitrarily big.
     116                 :            :          * With "plot", this causes arbitrarily wide output SVG files which almost
     117                 :            :          * completely consist of empty space. Thus we cancel out this offset.
     118                 :            :          *
     119                 :            :          * This offset is subtracted from times above by acquire_boot_times(),
     120                 :            :          * but it still needs to be subtracted from unit-specific timestamps
     121                 :            :          * (so it is stored here for reference).
     122                 :            :          */
     123                 :            :         usec_t reverse_offset;
     124                 :            : };
     125                 :            : 
     126                 :            : struct unit_times {
     127                 :            :         bool has_data;
     128                 :            :         char *name;
     129                 :            :         usec_t activating;
     130                 :            :         usec_t activated;
     131                 :            :         usec_t deactivated;
     132                 :            :         usec_t deactivating;
     133                 :            :         usec_t time;
     134                 :            : };
     135                 :            : 
     136                 :            : struct host_info {
     137                 :            :         char *hostname;
     138                 :            :         char *kernel_name;
     139                 :            :         char *kernel_release;
     140                 :            :         char *kernel_version;
     141                 :            :         char *os_pretty_name;
     142                 :            :         char *virtualization;
     143                 :            :         char *architecture;
     144                 :            : };
     145                 :            : 
     146                 :          0 : static int acquire_bus(sd_bus **bus, bool *use_full_bus) {
     147                 :          0 :         bool user = arg_scope != UNIT_FILE_SYSTEM;
     148                 :            :         int r;
     149                 :            : 
     150   [ #  #  #  # ]:          0 :         if (use_full_bus && *use_full_bus) {
     151                 :          0 :                 r = bus_connect_transport(arg_transport, arg_host, user, bus);
     152   [ #  #  #  # ]:          0 :                 if (IN_SET(r, 0, -EHOSTDOWN))
     153                 :          0 :                         return r;
     154                 :            : 
     155                 :          0 :                 *use_full_bus = false;
     156                 :            :         }
     157                 :            : 
     158                 :          0 :         return bus_connect_transport_systemd(arg_transport, arg_host, user, bus);
     159                 :            : }
     160                 :            : 
     161                 :          0 : static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
     162                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     163                 :            :         int r;
     164                 :            : 
     165         [ #  # ]:          0 :         assert(bus);
     166         [ #  # ]:          0 :         assert(path);
     167         [ #  # ]:          0 :         assert(interface);
     168         [ #  # ]:          0 :         assert(property);
     169         [ #  # ]:          0 :         assert(val);
     170                 :            : 
     171                 :          0 :         r = sd_bus_get_property_trivial(
     172                 :            :                         bus,
     173                 :            :                         "org.freedesktop.systemd1",
     174                 :            :                         path,
     175                 :            :                         interface,
     176                 :            :                         property,
     177                 :            :                         &error,
     178                 :            :                         't', val);
     179                 :            : 
     180         [ #  # ]:          0 :         if (r < 0)
     181         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to parse reply: %s", bus_error_message(&error, r));
     182                 :            : 
     183                 :          0 :         return 0;
     184                 :            : }
     185                 :            : 
     186                 :          0 : static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
     187                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     188                 :            :         int r;
     189                 :            : 
     190         [ #  # ]:          0 :         assert(bus);
     191         [ #  # ]:          0 :         assert(path);
     192         [ #  # ]:          0 :         assert(property);
     193         [ #  # ]:          0 :         assert(strv);
     194                 :            : 
     195                 :          0 :         r = sd_bus_get_property_strv(
     196                 :            :                         bus,
     197                 :            :                         "org.freedesktop.systemd1",
     198                 :            :                         path,
     199                 :            :                         "org.freedesktop.systemd1.Unit",
     200                 :            :                         property,
     201                 :            :                         &error,
     202                 :            :                         strv);
     203         [ #  # ]:          0 :         if (r < 0)
     204         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get unit property %s: %s", property, bus_error_message(&error, r));
     205                 :            : 
     206                 :          0 :         return 0;
     207                 :            : }
     208                 :            : 
     209                 :          0 : static int compare_unit_start(const struct unit_times *a, const struct unit_times *b) {
     210         [ #  # ]:          0 :         return CMP(a->activating, b->activating);
     211                 :            : }
     212                 :            : 
     213                 :          0 : static void unit_times_free(struct unit_times *t) {
     214                 :            :         struct unit_times *p;
     215                 :            : 
     216         [ #  # ]:          0 :         for (p = t; p->has_data; p++)
     217                 :          0 :                 free(p->name);
     218                 :          0 :         free(t);
     219                 :          0 : }
     220                 :            : 
     221         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(struct unit_times *, unit_times_free);
     222                 :            : 
     223                 :          0 : static void subtract_timestamp(usec_t *a, usec_t b) {
     224         [ #  # ]:          0 :         assert(a);
     225                 :            : 
     226         [ #  # ]:          0 :         if (*a > 0) {
     227         [ #  # ]:          0 :                 assert(*a >= b);
     228                 :          0 :                 *a -= b;
     229                 :            :         }
     230                 :          0 : }
     231                 :            : 
     232                 :          0 : static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
     233                 :            :         static const struct bus_properties_map property_map[] = {
     234                 :            :                 { "FirmwareTimestampMonotonic",               "t", NULL, offsetof(struct boot_times, firmware_time)                 },
     235                 :            :                 { "LoaderTimestampMonotonic",                 "t", NULL, offsetof(struct boot_times, loader_time)                   },
     236                 :            :                 { "KernelTimestamp",                          "t", NULL, offsetof(struct boot_times, kernel_time)                   },
     237                 :            :                 { "InitRDTimestampMonotonic",                 "t", NULL, offsetof(struct boot_times, initrd_time)                   },
     238                 :            :                 { "UserspaceTimestampMonotonic",              "t", NULL, offsetof(struct boot_times, userspace_time)                },
     239                 :            :                 { "FinishTimestampMonotonic",                 "t", NULL, offsetof(struct boot_times, finish_time)                   },
     240                 :            :                 { "SecurityStartTimestampMonotonic",          "t", NULL, offsetof(struct boot_times, security_start_time)           },
     241                 :            :                 { "SecurityFinishTimestampMonotonic",         "t", NULL, offsetof(struct boot_times, security_finish_time)          },
     242                 :            :                 { "GeneratorsStartTimestampMonotonic",        "t", NULL, offsetof(struct boot_times, generators_start_time)         },
     243                 :            :                 { "GeneratorsFinishTimestampMonotonic",       "t", NULL, offsetof(struct boot_times, generators_finish_time)        },
     244                 :            :                 { "UnitsLoadStartTimestampMonotonic",         "t", NULL, offsetof(struct boot_times, unitsload_start_time)          },
     245                 :            :                 { "UnitsLoadFinishTimestampMonotonic",        "t", NULL, offsetof(struct boot_times, unitsload_finish_time)         },
     246                 :            :                 { "InitRDSecurityStartTimestampMonotonic",    "t", NULL, offsetof(struct boot_times, initrd_security_start_time)    },
     247                 :            :                 { "InitRDSecurityFinishTimestampMonotonic",   "t", NULL, offsetof(struct boot_times, initrd_security_finish_time)   },
     248                 :            :                 { "InitRDGeneratorsStartTimestampMonotonic",  "t", NULL, offsetof(struct boot_times, initrd_generators_start_time)  },
     249                 :            :                 { "InitRDGeneratorsFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_generators_finish_time) },
     250                 :            :                 { "InitRDUnitsLoadStartTimestampMonotonic",   "t", NULL, offsetof(struct boot_times, initrd_unitsload_start_time)   },
     251                 :            :                 { "InitRDUnitsLoadFinishTimestampMonotonic",  "t", NULL, offsetof(struct boot_times, initrd_unitsload_finish_time)  },
     252                 :            :                 {},
     253                 :            :         };
     254                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     255                 :            :         static struct boot_times times;
     256                 :            :         static bool cached = false;
     257                 :            :         int r;
     258                 :            : 
     259         [ #  # ]:          0 :         if (cached)
     260                 :          0 :                 goto finish;
     261                 :            : 
     262                 :            :         assert_cc(sizeof(usec_t) == sizeof(uint64_t));
     263                 :            : 
     264                 :          0 :         r = bus_map_all_properties(
     265                 :            :                         bus,
     266                 :            :                         "org.freedesktop.systemd1",
     267                 :            :                         "/org/freedesktop/systemd1",
     268                 :            :                         property_map,
     269                 :            :                         BUS_MAP_STRDUP,
     270                 :            :                         &error,
     271                 :            :                         NULL,
     272                 :            :                         &times);
     273         [ #  # ]:          0 :         if (r < 0)
     274         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get timestamp properties: %s", bus_error_message(&error, r));
     275                 :            : 
     276         [ #  # ]:          0 :         if (times.finish_time <= 0)
     277   [ #  #  #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINPROGRESS),
     278                 :            :                                        "Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
     279                 :            :                                        "Please try again later.\n"
     280                 :            :                                        "Hint: Use 'systemctl%s list-jobs' to see active jobs",
     281                 :            :                                        times.finish_time,
     282                 :            :                                        arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
     283                 :            : 
     284   [ #  #  #  # ]:          0 :         if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) {
     285                 :            :                 /* security_start_time is set when systemd is not running under container environment. */
     286         [ #  # ]:          0 :                 if (times.initrd_time > 0)
     287                 :          0 :                         times.kernel_done_time = times.initrd_time;
     288                 :            :                 else
     289                 :          0 :                         times.kernel_done_time = times.userspace_time;
     290                 :            :         } else {
     291                 :            :                 /*
     292                 :            :                  * User-instance-specific or container-system-specific timestamps processing
     293                 :            :                  * (see comment to reverse_offset in struct boot_times).
     294                 :            :                  */
     295                 :          0 :                 times.reverse_offset = times.userspace_time;
     296                 :            : 
     297                 :          0 :                 times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time =
     298                 :          0 :                         times.userspace_time = times.security_start_time = times.security_finish_time = 0;
     299                 :            : 
     300                 :          0 :                 subtract_timestamp(&times.finish_time, times.reverse_offset);
     301                 :            : 
     302                 :          0 :                 subtract_timestamp(&times.generators_start_time, times.reverse_offset);
     303                 :          0 :                 subtract_timestamp(&times.generators_finish_time, times.reverse_offset);
     304                 :            : 
     305                 :          0 :                 subtract_timestamp(&times.unitsload_start_time, times.reverse_offset);
     306                 :          0 :                 subtract_timestamp(&times.unitsload_finish_time, times.reverse_offset);
     307                 :            :         }
     308                 :            : 
     309                 :          0 :         cached = true;
     310                 :            : 
     311                 :          0 : finish:
     312                 :          0 :         *bt = &times;
     313                 :          0 :         return 0;
     314                 :            : }
     315                 :            : 
     316                 :          0 : static void free_host_info(struct host_info *hi) {
     317         [ #  # ]:          0 :         if (!hi)
     318                 :          0 :                 return;
     319                 :            : 
     320                 :          0 :         free(hi->hostname);
     321                 :          0 :         free(hi->kernel_name);
     322                 :          0 :         free(hi->kernel_release);
     323                 :          0 :         free(hi->kernel_version);
     324                 :          0 :         free(hi->os_pretty_name);
     325                 :          0 :         free(hi->virtualization);
     326                 :          0 :         free(hi->architecture);
     327                 :          0 :         free(hi);
     328                 :            : }
     329                 :            : 
     330         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info *, free_host_info);
     331                 :            : 
     332                 :          0 : static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
     333                 :            :         static const struct bus_properties_map property_map[] = {
     334                 :            :                 { "InactiveExitTimestampMonotonic",  "t", NULL, offsetof(struct unit_times, activating)   },
     335                 :            :                 { "ActiveEnterTimestampMonotonic",   "t", NULL, offsetof(struct unit_times, activated)    },
     336                 :            :                 { "ActiveExitTimestampMonotonic",    "t", NULL, offsetof(struct unit_times, deactivating) },
     337                 :            :                 { "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(struct unit_times, deactivated)  },
     338                 :            :                 {},
     339                 :            :         };
     340                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     341                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     342                 :          0 :         _cleanup_(unit_times_freep) struct unit_times *unit_times = NULL;
     343                 :          0 :         struct boot_times *boot_times = NULL;
     344                 :          0 :         size_t allocated = 0, c = 0;
     345                 :            :         UnitInfo u;
     346                 :            :         int r;
     347                 :            : 
     348                 :          0 :         r = acquire_boot_times(bus, &boot_times);
     349         [ #  # ]:          0 :         if (r < 0)
     350                 :          0 :                 return r;
     351                 :            : 
     352                 :          0 :         r = sd_bus_call_method(
     353                 :            :                         bus,
     354                 :            :                         "org.freedesktop.systemd1",
     355                 :            :                         "/org/freedesktop/systemd1",
     356                 :            :                         "org.freedesktop.systemd1.Manager",
     357                 :            :                         "ListUnits",
     358                 :            :                         &error, &reply,
     359                 :            :                         NULL);
     360         [ #  # ]:          0 :         if (r < 0)
     361         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
     362                 :            : 
     363                 :          0 :         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
     364         [ #  # ]:          0 :         if (r < 0)
     365         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     366                 :            : 
     367         [ #  # ]:          0 :         while ((r = bus_parse_unit_info(reply, &u)) > 0) {
     368                 :            :                 struct unit_times *t;
     369                 :            : 
     370         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(unit_times, allocated, c + 2))
     371                 :          0 :                         return log_oom();
     372                 :            : 
     373                 :          0 :                 unit_times[c + 1].has_data = false;
     374                 :          0 :                 t = &unit_times[c];
     375                 :          0 :                 t->name = NULL;
     376                 :            : 
     377                 :            :                 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
     378                 :            : 
     379                 :          0 :                 r = bus_map_all_properties(
     380                 :            :                                 bus,
     381                 :            :                                 "org.freedesktop.systemd1",
     382                 :            :                                 u.unit_path,
     383                 :            :                                 property_map,
     384                 :            :                                 BUS_MAP_STRDUP,
     385                 :            :                                 &error,
     386                 :            :                                 NULL,
     387                 :            :                                 t);
     388         [ #  # ]:          0 :                 if (r < 0)
     389         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to get timestamp properties of unit %s: %s",
     390                 :            :                                                u.id, bus_error_message(&error, r));
     391                 :            : 
     392                 :          0 :                 subtract_timestamp(&t->activating, boot_times->reverse_offset);
     393                 :          0 :                 subtract_timestamp(&t->activated, boot_times->reverse_offset);
     394                 :          0 :                 subtract_timestamp(&t->deactivating, boot_times->reverse_offset);
     395                 :          0 :                 subtract_timestamp(&t->deactivated, boot_times->reverse_offset);
     396                 :            : 
     397         [ #  # ]:          0 :                 if (t->activated >= t->activating)
     398                 :          0 :                         t->time = t->activated - t->activating;
     399         [ #  # ]:          0 :                 else if (t->deactivated >= t->activating)
     400                 :          0 :                         t->time = t->deactivated - t->activating;
     401                 :            :                 else
     402                 :          0 :                         t->time = 0;
     403                 :            : 
     404         [ #  # ]:          0 :                 if (t->activating == 0)
     405                 :          0 :                         continue;
     406                 :            : 
     407                 :          0 :                 t->name = strdup(u.id);
     408         [ #  # ]:          0 :                 if (!t->name)
     409                 :          0 :                         return log_oom();
     410                 :            : 
     411                 :          0 :                 t->has_data = true;
     412                 :          0 :                 c++;
     413                 :            :         }
     414         [ #  # ]:          0 :         if (r < 0)
     415         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     416                 :            : 
     417                 :          0 :         *out = TAKE_PTR(unit_times);
     418                 :          0 :         return c;
     419                 :            : }
     420                 :            : 
     421                 :          0 : static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
     422                 :            :         static const struct bus_properties_map hostname_map[] = {
     423                 :            :                 { "Hostname",                  "s", NULL, offsetof(struct host_info, hostname)       },
     424                 :            :                 { "KernelName",                "s", NULL, offsetof(struct host_info, kernel_name)    },
     425                 :            :                 { "KernelRelease",             "s", NULL, offsetof(struct host_info, kernel_release) },
     426                 :            :                 { "KernelVersion",             "s", NULL, offsetof(struct host_info, kernel_version) },
     427                 :            :                 { "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) },
     428                 :            :                 {}
     429                 :            :         };
     430                 :            : 
     431                 :            :         static const struct bus_properties_map manager_map[] = {
     432                 :            :                 { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
     433                 :            :                 { "Architecture",   "s", NULL, offsetof(struct host_info, architecture)   },
     434                 :            :                 {}
     435                 :            :         };
     436                 :            : 
     437                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     438                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL;
     439                 :          0 :         _cleanup_(free_host_infop) struct host_info *host;
     440                 :            :         int r;
     441                 :            : 
     442                 :          0 :         host = new0(struct host_info, 1);
     443         [ #  # ]:          0 :         if (!host)
     444                 :          0 :                 return log_oom();
     445                 :            : 
     446         [ #  # ]:          0 :         if (arg_scope != UNIT_FILE_SYSTEM) {
     447                 :          0 :                 r = bus_connect_transport(arg_transport, arg_host, false, &system_bus);
     448         [ #  # ]:          0 :                 if (r < 0) {
     449         [ #  # ]:          0 :                         log_debug_errno(r, "Failed to connect to system bus, ignoring: %m");
     450                 :          0 :                         goto manager;
     451                 :            :                 }
     452                 :            :         }
     453                 :            : 
     454                 :          0 :         r = bus_map_all_properties(
     455         [ #  # ]:          0 :                         system_bus ?: bus,
     456                 :            :                         "org.freedesktop.hostname1",
     457                 :            :                         "/org/freedesktop/hostname1",
     458                 :            :                         hostname_map,
     459                 :            :                         BUS_MAP_STRDUP,
     460                 :            :                         &error,
     461                 :            :                         NULL,
     462                 :            :                         host);
     463         [ #  # ]:          0 :         if (r < 0) {
     464         [ #  # ]:          0 :                 log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s",
     465                 :            :                                 bus_error_message(&error, r));
     466                 :          0 :                 sd_bus_error_free(&error);
     467                 :            :         }
     468                 :            : 
     469                 :          0 : manager:
     470                 :          0 :         r = bus_map_all_properties(
     471                 :            :                         bus,
     472                 :            :                         "org.freedesktop.systemd1",
     473                 :            :                         "/org/freedesktop/systemd1",
     474                 :            :                         manager_map,
     475                 :            :                         BUS_MAP_STRDUP,
     476                 :            :                         &error,
     477                 :            :                         NULL,
     478                 :            :                         host);
     479         [ #  # ]:          0 :         if (r < 0)
     480         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get host information from systemd: %s",
     481                 :            :                                        bus_error_message(&error, r));
     482                 :            : 
     483                 :          0 :         *hi = TAKE_PTR(host);
     484                 :          0 :         return 0;
     485                 :            : }
     486                 :            : 
     487                 :          0 : static int pretty_boot_time(sd_bus *bus, char **_buf) {
     488                 :            :         char ts[FORMAT_TIMESPAN_MAX];
     489                 :            :         struct boot_times *t;
     490                 :            :         static char buf[4096];
     491                 :            :         size_t size;
     492                 :            :         char *ptr;
     493                 :            :         int r;
     494                 :          0 :         usec_t activated_time = USEC_INFINITY;
     495                 :          0 :         _cleanup_free_ char *path = NULL, *unit_id = NULL;
     496                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     497                 :            : 
     498                 :          0 :         r = acquire_boot_times(bus, &t);
     499         [ #  # ]:          0 :         if (r < 0)
     500                 :          0 :                 return r;
     501                 :            : 
     502                 :          0 :         path = unit_dbus_path_from_name(SPECIAL_DEFAULT_TARGET);
     503         [ #  # ]:          0 :         if (!path)
     504                 :          0 :                 return log_oom();
     505                 :            : 
     506                 :          0 :         r = sd_bus_get_property_string(
     507                 :            :                         bus,
     508                 :            :                         "org.freedesktop.systemd1",
     509                 :            :                         path,
     510                 :            :                         "org.freedesktop.systemd1.Unit",
     511                 :            :                         "Id",
     512                 :            :                         &error,
     513                 :            :                         &unit_id);
     514         [ #  # ]:          0 :         if (r < 0) {
     515         [ #  # ]:          0 :                 log_error_errno(r, "default.target doesn't seem to exist: %s", bus_error_message(&error, r));
     516                 :          0 :                 unit_id = NULL;
     517                 :            :         }
     518                 :            : 
     519                 :          0 :         r = bus_get_uint64_property(bus, path,
     520                 :            :                         "org.freedesktop.systemd1.Unit",
     521                 :            :                         "ActiveEnterTimestampMonotonic",
     522                 :            :                         &activated_time);
     523         [ #  # ]:          0 :         if (r < 0) {
     524         [ #  # ]:          0 :                 log_info_errno(r, "Could not get time to reach default.target, ignoring: %m");
     525                 :          0 :                 activated_time = USEC_INFINITY;
     526                 :            :         }
     527                 :            : 
     528                 :          0 :         ptr = buf;
     529                 :          0 :         size = sizeof(buf);
     530                 :            : 
     531                 :          0 :         size = strpcpyf(&ptr, size, "Startup finished in ");
     532         [ #  # ]:          0 :         if (t->firmware_time > 0)
     533                 :          0 :                 size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
     534         [ #  # ]:          0 :         if (t->loader_time > 0)
     535                 :          0 :                 size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
     536         [ #  # ]:          0 :         if (t->kernel_done_time > 0)
     537                 :          0 :                 size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
     538         [ #  # ]:          0 :         if (t->initrd_time > 0)
     539                 :          0 :                 size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
     540                 :            : 
     541                 :          0 :         size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
     542         [ #  # ]:          0 :         if (t->kernel_done_time > 0)
     543                 :          0 :                 strpcpyf(&ptr, size, "= %s ", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
     544                 :            : 
     545   [ #  #  #  # ]:          0 :         if (unit_id && timestamp_is_set(activated_time)) {
     546         [ #  # ]:          0 :                 usec_t base = t->userspace_time > 0 ? t->userspace_time : t->reverse_offset;
     547                 :            : 
     548                 :          0 :                 size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id,
     549                 :            :                                 format_timespan(ts, sizeof(ts), activated_time - base, USEC_PER_MSEC));
     550   [ #  #  #  # ]:          0 :         } else if (unit_id && activated_time == 0)
     551                 :          0 :                 size = strpcpyf(&ptr, size, "\n%s was never reached", unit_id);
     552   [ #  #  #  # ]:          0 :         else if (unit_id && activated_time == USEC_INFINITY)
     553                 :          0 :                 size = strpcpyf(&ptr, size, "\nCould not get time to reach %s.", unit_id);
     554         [ #  # ]:          0 :         else if (!unit_id)
     555                 :          0 :                 size = strpcpyf(&ptr, size, "\ncould not find default.target");
     556                 :            : 
     557                 :          0 :         ptr = strdup(buf);
     558         [ #  # ]:          0 :         if (!ptr)
     559                 :          0 :                 return log_oom();
     560                 :            : 
     561                 :          0 :         *_buf = ptr;
     562                 :          0 :         return 0;
     563                 :            : }
     564                 :            : 
     565                 :          0 : static void svg_graph_box(double height, double begin, double end) {
     566                 :            :         long long i;
     567                 :            : 
     568                 :            :         /* outside box, fill */
     569                 :          0 :         svg("<rect class=\"box\" x=\"0\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
     570                 :            :             SCALE_X * (end - begin),
     571                 :            :             SCALE_Y * height);
     572                 :            : 
     573         [ #  # ]:          0 :         for (i = ((long long) (begin / 100000)) * 100000; i <= end; i += 100000) {
     574                 :            :                 /* lines for each second */
     575         [ #  # ]:          0 :                 if (i % 5000000 == 0)
     576                 :          0 :                         svg("  <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
     577                 :            :                             "  <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
     578                 :            :                             SCALE_X * i,
     579                 :            :                             SCALE_X * i,
     580                 :            :                             SCALE_Y * height,
     581                 :            :                             SCALE_X * i,
     582                 :            :                             -5.0,
     583                 :            :                             0.000001 * i);
     584         [ #  # ]:          0 :                 else if (i % 1000000 == 0)
     585                 :          0 :                         svg("  <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
     586                 :            :                             "  <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
     587                 :            :                             SCALE_X * i,
     588                 :            :                             SCALE_X * i,
     589                 :            :                             SCALE_Y * height,
     590                 :            :                             SCALE_X * i,
     591                 :            :                             -5.0,
     592                 :            :                             0.000001 * i);
     593                 :            :                 else
     594                 :          0 :                         svg("  <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
     595                 :            :                             SCALE_X * i,
     596                 :            :                             SCALE_X * i,
     597                 :            :                             SCALE_Y * height);
     598                 :            :         }
     599                 :          0 : }
     600                 :            : 
     601                 :          0 : static int plot_unit_times(struct unit_times *u, double width, int y) {
     602                 :            :         char ts[FORMAT_TIMESPAN_MAX];
     603                 :            :         bool b;
     604                 :            : 
     605         [ #  # ]:          0 :         if (!u->name)
     606                 :          0 :                 return 0;
     607                 :            : 
     608                 :          0 :         svg_bar("activating",   u->activating, u->activated, y);
     609                 :          0 :         svg_bar("active",       u->activated, u->deactivating, y);
     610                 :          0 :         svg_bar("deactivating", u->deactivating, u->deactivated, y);
     611                 :            : 
     612                 :            :         /* place the text on the left if we have passed the half of the svg width */
     613                 :          0 :         b = u->activating * SCALE_X < width / 2;
     614         [ #  # ]:          0 :         if (u->time)
     615   [ #  #  #  # ]:          0 :                 svg_text(b, u->activating, y, "%s (%s)",
     616                 :            :                          u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
     617                 :            :         else
     618   [ #  #  #  # ]:          0 :                 svg_text(b, u->activating, y, "%s", u->name);
     619                 :            : 
     620                 :          0 :         return 1;
     621                 :            : }
     622                 :            : 
     623                 :          0 : static int analyze_plot(int argc, char *argv[], void *userdata) {
     624                 :          0 :         _cleanup_(free_host_infop) struct host_info *host = NULL;
     625                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     626                 :          0 :         _cleanup_(unit_times_freep) struct unit_times *times = NULL;
     627                 :          0 :         _cleanup_free_ char *pretty_times = NULL;
     628                 :          0 :         bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM;
     629                 :            :         struct boot_times *boot;
     630                 :            :         struct unit_times *u;
     631                 :          0 :         int n, m = 1, y = 0, r;
     632                 :            :         double width;
     633                 :            : 
     634                 :          0 :         r = acquire_bus(&bus, &use_full_bus);
     635         [ #  # ]:          0 :         if (r < 0)
     636         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
     637                 :            : 
     638                 :          0 :         n = acquire_boot_times(bus, &boot);
     639         [ #  # ]:          0 :         if (n < 0)
     640                 :          0 :                 return n;
     641                 :            : 
     642                 :          0 :         n = pretty_boot_time(bus, &pretty_times);
     643         [ #  # ]:          0 :         if (n < 0)
     644                 :          0 :                 return n;
     645                 :            : 
     646   [ #  #  #  # ]:          0 :         if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) {
     647                 :          0 :                 n = acquire_host_info(bus, &host);
     648         [ #  # ]:          0 :                 if (n < 0)
     649                 :          0 :                         return n;
     650                 :            :         }
     651                 :            : 
     652                 :          0 :         n = acquire_time_data(bus, &times);
     653         [ #  # ]:          0 :         if (n <= 0)
     654                 :          0 :                 return n;
     655                 :            : 
     656                 :          0 :         typesafe_qsort(times, n, compare_unit_start);
     657                 :            : 
     658                 :          0 :         width = SCALE_X * (boot->firmware_time + boot->finish_time);
     659         [ #  # ]:          0 :         if (width < 800.0)
     660                 :          0 :                 width = 800.0;
     661                 :            : 
     662         [ #  # ]:          0 :         if (boot->firmware_time > boot->loader_time)
     663                 :          0 :                 m++;
     664         [ #  # ]:          0 :         if (boot->loader_time > 0) {
     665                 :          0 :                 m++;
     666         [ #  # ]:          0 :                 if (width < 1000.0)
     667                 :          0 :                         width = 1000.0;
     668                 :            :         }
     669         [ #  # ]:          0 :         if (boot->initrd_time > 0)
     670                 :          0 :                 m++;
     671         [ #  # ]:          0 :         if (boot->kernel_done_time > 0)
     672                 :          0 :                 m++;
     673                 :            : 
     674         [ #  # ]:          0 :         for (u = times; u->has_data; u++) {
     675                 :            :                 double text_start, text_width;
     676                 :            : 
     677         [ #  # ]:          0 :                 if (u->activating > boot->finish_time) {
     678                 :          0 :                         u->name = mfree(u->name);
     679                 :          0 :                         continue;
     680                 :            :                 }
     681                 :            : 
     682                 :            :                 /* If the text cannot fit on the left side then
     683                 :            :                  * increase the svg width so it fits on the right.
     684                 :            :                  * TODO: calculate the text width more accurately */
     685                 :          0 :                 text_width = 8.0 * strlen(u->name);
     686                 :          0 :                 text_start = (boot->firmware_time + u->activating) * SCALE_X;
     687   [ #  #  #  # ]:          0 :                 if (text_width > text_start && text_width + text_start > width)
     688                 :          0 :                         width = text_width + text_start;
     689                 :            : 
     690         [ #  # ]:          0 :                 if (u->deactivated > u->activating &&
     691         [ #  # ]:          0 :                     u->deactivated <= boot->finish_time &&
     692   [ #  #  #  # ]:          0 :                     u->activated == 0 && u->deactivating == 0)
     693                 :          0 :                         u->activated = u->deactivating = u->deactivated;
     694   [ #  #  #  # ]:          0 :                 if (u->activated < u->activating || u->activated > boot->finish_time)
     695                 :          0 :                         u->activated = boot->finish_time;
     696   [ #  #  #  # ]:          0 :                 if (u->deactivating < u->activated || u->deactivating > boot->finish_time)
     697                 :          0 :                         u->deactivating = boot->finish_time;
     698   [ #  #  #  # ]:          0 :                 if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time)
     699                 :          0 :                         u->deactivated = boot->finish_time;
     700                 :          0 :                 m++;
     701                 :            :         }
     702                 :            : 
     703                 :          0 :         svg("<?xml version=\"1.0\" standalone=\"no\"?>\n"
     704                 :            :             "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
     705                 :            :             "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
     706                 :            : 
     707                 :          0 :         svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" "
     708                 :            :             "xmlns=\"http://www.w3.org/2000/svg\">\n\n",
     709                 :            :                         80.0 + width, 150.0 + (m * SCALE_Y) +
     710                 :            :                         5 * SCALE_Y /* legend */);
     711                 :            : 
     712                 :            :         /* write some basic info as a comment, including some help */
     713                 :          0 :         svg("<!-- This file is a systemd-analyze SVG file. It is best rendered in a   -->\n"
     714                 :            :             "<!-- browser such as Chrome, Chromium or Firefox. Other applications     -->\n"
     715                 :            :             "<!-- that render these files properly but much slower are ImageMagick,   -->\n"
     716                 :            :             "<!-- gimp, inkscape, etc. To display the files on your system, just      -->\n"
     717                 :            :             "<!-- point your browser to this file.                                    -->\n\n"
     718                 :            :             "<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", GIT_VERSION);
     719                 :            : 
     720                 :            :         /* style sheet */
     721                 :          0 :         svg("<defs>\n  <style type=\"text/css\">\n    <![CDATA[\n"
     722                 :            :             "      rect       { stroke-width: 1; stroke-opacity: 0; }\n"
     723                 :            :             "      rect.background   { fill: rgb(255,255,255); }\n"
     724                 :            :             "      rect.activating   { fill: rgb(255,0,0); fill-opacity: 0.7; }\n"
     725                 :            :             "      rect.active       { fill: rgb(200,150,150); fill-opacity: 0.7; }\n"
     726                 :            :             "      rect.deactivating { fill: rgb(150,100,100); fill-opacity: 0.7; }\n"
     727                 :            :             "      rect.kernel       { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
     728                 :            :             "      rect.initrd       { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
     729                 :            :             "      rect.firmware     { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
     730                 :            :             "      rect.loader       { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
     731                 :            :             "      rect.userspace    { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
     732                 :            :             "      rect.security     { fill: rgb(144,238,144); fill-opacity: 0.7; }\n"
     733                 :            :             "      rect.generators   { fill: rgb(102,204,255); fill-opacity: 0.7; }\n"
     734                 :            :             "      rect.unitsload    { fill: rgb( 82,184,255); fill-opacity: 0.7; }\n"
     735                 :            :             "      rect.box   { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n"
     736                 :            :             "      line       { stroke: rgb(64,64,64); stroke-width: 1; }\n"
     737                 :            :             "//    line.sec1  { }\n"
     738                 :            :             "      line.sec5  { stroke-width: 2; }\n"
     739                 :            :             "      line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n"
     740                 :            :             "      text       { font-family: Verdana, Helvetica; font-size: 14px; }\n"
     741                 :            :             "      text.left  { font-family: Verdana, Helvetica; font-size: 14px; text-anchor: start; }\n"
     742                 :            :             "      text.right { font-family: Verdana, Helvetica; font-size: 14px; text-anchor: end; }\n"
     743                 :            :             "      text.sec   { font-size: 10px; }\n"
     744                 :            :             "    ]]>\n   </style>\n</defs>\n\n");
     745                 :            : 
     746                 :          0 :         svg("<rect class=\"background\" width=\"100%%\" height=\"100%%\" />\n");
     747                 :          0 :         svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
     748         [ #  # ]:          0 :         if (host)
     749         [ #  # ]:          0 :                 svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>",
     750                 :            :                     isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
     751                 :            :                     strempty(host->hostname),
     752                 :            :                     strempty(host->kernel_name),
     753                 :            :                     strempty(host->kernel_release),
     754                 :            :                     strempty(host->kernel_version),
     755                 :            :                     strempty(host->architecture),
     756                 :            :                     strempty(host->virtualization));
     757                 :            : 
     758                 :          0 :         svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
     759                 :          0 :         svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
     760                 :            : 
     761         [ #  # ]:          0 :         if (boot->firmware_time > 0) {
     762                 :          0 :                 svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y);
     763                 :          0 :                 svg_text(true, -(double) boot->firmware_time, y, "firmware");
     764                 :          0 :                 y++;
     765                 :            :         }
     766         [ #  # ]:          0 :         if (boot->loader_time > 0) {
     767                 :          0 :                 svg_bar("loader", -(double) boot->loader_time, 0, y);
     768                 :          0 :                 svg_text(true, -(double) boot->loader_time, y, "loader");
     769                 :          0 :                 y++;
     770                 :            :         }
     771         [ #  # ]:          0 :         if (boot->kernel_done_time > 0) {
     772                 :          0 :                 svg_bar("kernel", 0, boot->kernel_done_time, y);
     773                 :          0 :                 svg_text(true, 0, y, "kernel");
     774                 :          0 :                 y++;
     775                 :            :         }
     776         [ #  # ]:          0 :         if (boot->initrd_time > 0) {
     777                 :          0 :                 svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
     778         [ #  # ]:          0 :                 if (boot->initrd_security_start_time < boot->initrd_security_finish_time)
     779                 :          0 :                         svg_bar("security", boot->initrd_security_start_time, boot->initrd_security_finish_time, y);
     780         [ #  # ]:          0 :                 if (boot->initrd_generators_start_time < boot->initrd_generators_finish_time)
     781                 :          0 :                         svg_bar("generators", boot->initrd_generators_start_time, boot->initrd_generators_finish_time, y);
     782         [ #  # ]:          0 :                 if (boot->initrd_unitsload_start_time < boot->initrd_unitsload_finish_time)
     783                 :          0 :                         svg_bar("unitsload", boot->initrd_unitsload_start_time, boot->initrd_unitsload_finish_time, y);
     784                 :          0 :                 svg_text(true, boot->initrd_time, y, "initrd");
     785                 :          0 :                 y++;
     786                 :            :         }
     787                 :            : 
     788         [ #  # ]:          0 :         for (u = times; u->has_data; u++) {
     789         [ #  # ]:          0 :                 if (u->activating >= boot->userspace_time)
     790                 :          0 :                         break;
     791                 :            : 
     792                 :          0 :                 y += plot_unit_times(u, width, y);
     793                 :            :         }
     794                 :            : 
     795                 :          0 :         svg_bar("active", boot->userspace_time, boot->finish_time, y);
     796         [ #  # ]:          0 :         if (boot->security_start_time > 0)
     797                 :          0 :                 svg_bar("security", boot->security_start_time, boot->security_finish_time, y);
     798                 :          0 :         svg_bar("generators", boot->generators_start_time, boot->generators_finish_time, y);
     799                 :          0 :         svg_bar("unitsload", boot->unitsload_start_time, boot->unitsload_finish_time, y);
     800                 :          0 :         svg_text(true, boot->userspace_time, y, "systemd");
     801                 :          0 :         y++;
     802                 :            : 
     803         [ #  # ]:          0 :         for (; u->has_data; u++)
     804                 :          0 :                 y += plot_unit_times(u, width, y);
     805                 :            : 
     806                 :          0 :         svg("</g>\n");
     807                 :            : 
     808                 :            :         /* Legend */
     809                 :          0 :         svg("<g transform=\"translate(20,100)\">\n");
     810                 :          0 :         y++;
     811                 :          0 :         svg_bar("activating", 0, 300000, y);
     812                 :          0 :         svg_text(true, 400000, y, "Activating");
     813                 :          0 :         y++;
     814                 :          0 :         svg_bar("active", 0, 300000, y);
     815                 :          0 :         svg_text(true, 400000, y, "Active");
     816                 :          0 :         y++;
     817                 :          0 :         svg_bar("deactivating", 0, 300000, y);
     818                 :          0 :         svg_text(true, 400000, y, "Deactivating");
     819                 :          0 :         y++;
     820         [ #  # ]:          0 :         if (boot->security_start_time > 0) {
     821                 :          0 :                 svg_bar("security", 0, 300000, y);
     822                 :          0 :                 svg_text(true, 400000, y, "Setting up security module");
     823                 :          0 :                 y++;
     824                 :            :         }
     825                 :          0 :         svg_bar("generators", 0, 300000, y);
     826                 :          0 :         svg_text(true, 400000, y, "Generators");
     827                 :          0 :         y++;
     828                 :          0 :         svg_bar("unitsload", 0, 300000, y);
     829                 :          0 :         svg_text(true, 400000, y, "Loading unit files");
     830                 :          0 :         y++;
     831                 :            : 
     832                 :          0 :         svg("</g>\n\n");
     833                 :            : 
     834                 :          0 :         svg("</svg>\n");
     835                 :            : 
     836                 :          0 :         return 0;
     837                 :            : }
     838                 :            : 
     839                 :          0 : static int list_dependencies_print(
     840                 :            :                 const char *name,
     841                 :            :                 unsigned level,
     842                 :            :                 unsigned branches,
     843                 :            :                 bool last,
     844                 :            :                 struct unit_times *times,
     845                 :            :                 struct boot_times *boot) {
     846                 :            : 
     847                 :            :         unsigned i;
     848                 :            :         char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
     849                 :            : 
     850         [ #  # ]:          0 :         for (i = level; i != 0; i--)
     851         [ #  # ]:          0 :                 printf("%s", special_glyph(branches & (1 << (i-1)) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
     852                 :            : 
     853         [ #  # ]:          0 :         printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
     854                 :            : 
     855         [ #  # ]:          0 :         if (times) {
     856         [ #  # ]:          0 :                 if (times->time > 0)
     857                 :          0 :                         printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
     858                 :          0 :                                format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
     859                 :            :                                format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal());
     860         [ #  # ]:          0 :                 else if (times->activated > boot->userspace_time)
     861                 :          0 :                         printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
     862                 :            :                 else
     863                 :          0 :                         printf("%s", name);
     864                 :            :         } else
     865                 :          0 :                 printf("%s", name);
     866                 :          0 :         printf("\n");
     867                 :            : 
     868                 :          0 :         return 0;
     869                 :            : }
     870                 :            : 
     871                 :          0 : static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
     872                 :          0 :         _cleanup_free_ char *path = NULL;
     873                 :            : 
     874         [ #  # ]:          0 :         assert(bus);
     875         [ #  # ]:          0 :         assert(name);
     876         [ #  # ]:          0 :         assert(deps);
     877                 :            : 
     878                 :          0 :         path = unit_dbus_path_from_name(name);
     879         [ #  # ]:          0 :         if (!path)
     880                 :          0 :                 return -ENOMEM;
     881                 :            : 
     882                 :          0 :         return bus_get_unit_property_strv(bus, path, "After", deps);
     883                 :            : }
     884                 :            : 
     885                 :            : static Hashmap *unit_times_hashmap;
     886                 :            : 
     887                 :          0 : static int list_dependencies_compare(char *const *a, char *const *b) {
     888                 :          0 :         usec_t usa = 0, usb = 0;
     889                 :            :         struct unit_times *times;
     890                 :            : 
     891                 :          0 :         times = hashmap_get(unit_times_hashmap, *a);
     892         [ #  # ]:          0 :         if (times)
     893                 :          0 :                 usa = times->activated;
     894                 :          0 :         times = hashmap_get(unit_times_hashmap, *b);
     895         [ #  # ]:          0 :         if (times)
     896                 :          0 :                 usb = times->activated;
     897                 :            : 
     898         [ #  # ]:          0 :         return CMP(usb, usa);
     899                 :            : }
     900                 :            : 
     901                 :          0 : static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) {
     902   [ #  #  #  #  :          0 :         return times && times->activated > 0 && times->activated <= boot->finish_time;
                   #  # ]
     903                 :            : }
     904                 :            : 
     905                 :          0 : static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units, unsigned branches) {
     906                 :          0 :         _cleanup_strv_free_ char **deps = NULL;
     907                 :            :         char **c;
     908                 :          0 :         int r = 0;
     909                 :          0 :         usec_t service_longest = 0;
     910                 :          0 :         int to_print = 0;
     911                 :            :         struct unit_times *times;
     912                 :            :         struct boot_times *boot;
     913                 :            : 
     914         [ #  # ]:          0 :         if (strv_extend(units, name))
     915                 :          0 :                 return log_oom();
     916                 :            : 
     917                 :          0 :         r = list_dependencies_get_dependencies(bus, name, &deps);
     918         [ #  # ]:          0 :         if (r < 0)
     919                 :          0 :                 return r;
     920                 :            : 
     921                 :          0 :         typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
     922                 :            : 
     923                 :          0 :         r = acquire_boot_times(bus, &boot);
     924         [ #  # ]:          0 :         if (r < 0)
     925                 :          0 :                 return r;
     926                 :            : 
     927   [ #  #  #  # ]:          0 :         STRV_FOREACH(c, deps) {
     928                 :          0 :                 times = hashmap_get(unit_times_hashmap, *c);
     929   [ #  #  #  # ]:          0 :                 if (times_in_range(times, boot) && times->activated >= service_longest)
     930                 :          0 :                         service_longest = times->activated;
     931                 :            :         }
     932                 :            : 
     933         [ #  # ]:          0 :         if (service_longest == 0)
     934                 :          0 :                 return r;
     935                 :            : 
     936   [ #  #  #  # ]:          0 :         STRV_FOREACH(c, deps) {
     937                 :          0 :                 times = hashmap_get(unit_times_hashmap, *c);
     938   [ #  #  #  # ]:          0 :                 if (times_in_range(times, boot) && service_longest - times->activated <= arg_fuzz)
     939                 :          0 :                         to_print++;
     940                 :            :         }
     941                 :            : 
     942         [ #  # ]:          0 :         if (!to_print)
     943                 :          0 :                 return r;
     944                 :            : 
     945   [ #  #  #  # ]:          0 :         STRV_FOREACH(c, deps) {
     946                 :          0 :                 times = hashmap_get(unit_times_hashmap, *c);
     947   [ #  #  #  # ]:          0 :                 if (!times_in_range(times, boot) || service_longest - times->activated > arg_fuzz)
     948                 :          0 :                         continue;
     949                 :            : 
     950                 :          0 :                 to_print--;
     951                 :            : 
     952                 :          0 :                 r = list_dependencies_print(*c, level, branches, to_print == 0, times, boot);
     953         [ #  # ]:          0 :                 if (r < 0)
     954                 :          0 :                         return r;
     955                 :            : 
     956         [ #  # ]:          0 :                 if (strv_contains(*units, *c)) {
     957         [ #  # ]:          0 :                         r = list_dependencies_print("...", level + 1, (branches << 1) | (to_print ? 1 : 0),
     958                 :            :                                                     true, NULL, boot);
     959         [ #  # ]:          0 :                         if (r < 0)
     960                 :          0 :                                 return r;
     961                 :          0 :                         continue;
     962                 :            :                 }
     963                 :            : 
     964         [ #  # ]:          0 :                 r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (to_print ? 1 : 0));
     965         [ #  # ]:          0 :                 if (r < 0)
     966                 :          0 :                         return r;
     967                 :            : 
     968         [ #  # ]:          0 :                 if (to_print == 0)
     969                 :          0 :                         break;
     970                 :            :         }
     971                 :          0 :         return 0;
     972                 :            : }
     973                 :            : 
     974                 :          0 : static int list_dependencies(sd_bus *bus, const char *name) {
     975                 :          0 :         _cleanup_strv_free_ char **units = NULL;
     976                 :            :         char ts[FORMAT_TIMESPAN_MAX];
     977                 :            :         struct unit_times *times;
     978                 :            :         int r;
     979                 :            :         const char *id;
     980                 :          0 :         _cleanup_free_ char *path = NULL;
     981                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     982                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     983                 :            :         struct boot_times *boot;
     984                 :            : 
     985         [ #  # ]:          0 :         assert(bus);
     986                 :            : 
     987                 :          0 :         path = unit_dbus_path_from_name(name);
     988         [ #  # ]:          0 :         if (!path)
     989                 :          0 :                 return -ENOMEM;
     990                 :            : 
     991                 :          0 :         r = sd_bus_get_property(
     992                 :            :                         bus,
     993                 :            :                         "org.freedesktop.systemd1",
     994                 :            :                         path,
     995                 :            :                         "org.freedesktop.systemd1.Unit",
     996                 :            :                         "Id",
     997                 :            :                         &error,
     998                 :            :                         &reply,
     999                 :            :                         "s");
    1000         [ #  # ]:          0 :         if (r < 0)
    1001         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
    1002                 :            : 
    1003                 :          0 :         r = sd_bus_message_read(reply, "s", &id);
    1004         [ #  # ]:          0 :         if (r < 0)
    1005         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1006                 :            : 
    1007                 :          0 :         times = hashmap_get(unit_times_hashmap, id);
    1008                 :            : 
    1009                 :          0 :         r = acquire_boot_times(bus, &boot);
    1010         [ #  # ]:          0 :         if (r < 0)
    1011                 :          0 :                 return r;
    1012                 :            : 
    1013         [ #  # ]:          0 :         if (times) {
    1014         [ #  # ]:          0 :                 if (times->time)
    1015                 :          0 :                         printf("%s%s +%s%s\n", ansi_highlight_red(), id,
    1016                 :            :                                format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ansi_normal());
    1017         [ #  # ]:          0 :                 else if (times->activated > boot->userspace_time)
    1018                 :          0 :                         printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
    1019                 :            :                 else
    1020                 :          0 :                         printf("%s\n", id);
    1021                 :            :         }
    1022                 :            : 
    1023                 :          0 :         return list_dependencies_one(bus, name, 0, &units, 0);
    1024                 :            : }
    1025                 :            : 
    1026                 :          0 : static int analyze_critical_chain(int argc, char *argv[], void *userdata) {
    1027                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1028                 :          0 :         _cleanup_(unit_times_freep) struct unit_times *times = NULL;
    1029                 :            :         struct unit_times *u;
    1030                 :            :         Hashmap *h;
    1031                 :            :         int n, r;
    1032                 :            : 
    1033                 :          0 :         r = acquire_bus(&bus, NULL);
    1034         [ #  # ]:          0 :         if (r < 0)
    1035         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1036                 :            : 
    1037                 :          0 :         n = acquire_time_data(bus, &times);
    1038         [ #  # ]:          0 :         if (n <= 0)
    1039                 :          0 :                 return n;
    1040                 :            : 
    1041                 :          0 :         h = hashmap_new(&string_hash_ops);
    1042         [ #  # ]:          0 :         if (!h)
    1043                 :          0 :                 return log_oom();
    1044                 :            : 
    1045         [ #  # ]:          0 :         for (u = times; u->has_data; u++) {
    1046                 :          0 :                 r = hashmap_put(h, u->name, u);
    1047         [ #  # ]:          0 :                 if (r < 0)
    1048         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to add entry to hashmap: %m");
    1049                 :            :         }
    1050                 :          0 :         unit_times_hashmap = h;
    1051                 :            : 
    1052                 :          0 :         (void) pager_open(arg_pager_flags);
    1053                 :            : 
    1054                 :          0 :         puts("The time when unit became active or started is printed after the \"@\" character.\n"
    1055                 :            :              "The time the unit took to start is printed after the \"+\" character.\n");
    1056                 :            : 
    1057         [ #  # ]:          0 :         if (argc > 1) {
    1058                 :            :                 char **name;
    1059   [ #  #  #  # ]:          0 :                 STRV_FOREACH(name, strv_skip(argv, 1))
    1060                 :          0 :                         list_dependencies(bus, *name);
    1061                 :            :         } else
    1062                 :          0 :                 list_dependencies(bus, SPECIAL_DEFAULT_TARGET);
    1063                 :            : 
    1064                 :          0 :         h = hashmap_free(h);
    1065                 :          0 :         return 0;
    1066                 :            : }
    1067                 :            : 
    1068                 :          0 : static int analyze_blame(int argc, char *argv[], void *userdata) {
    1069                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1070                 :          0 :         _cleanup_(unit_times_freep) struct unit_times *times = NULL;
    1071                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1072                 :            :         struct unit_times *u;
    1073                 :            :         TableCell *cell;
    1074                 :            :         int n, r;
    1075                 :            : 
    1076                 :          0 :         r = acquire_bus(&bus, NULL);
    1077         [ #  # ]:          0 :         if (r < 0)
    1078         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1079                 :            : 
    1080                 :          0 :         n = acquire_time_data(bus, &times);
    1081         [ #  # ]:          0 :         if (n <= 0)
    1082                 :          0 :                 return n;
    1083                 :            : 
    1084                 :          0 :         table = table_new("time", "unit");
    1085         [ #  # ]:          0 :         if (!table)
    1086                 :          0 :                 return log_oom();
    1087                 :            : 
    1088                 :          0 :         table_set_header(table, false);
    1089                 :            : 
    1090         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1091                 :          0 :         r = table_set_ellipsize_percent(table, cell, 100);
    1092         [ #  # ]:          0 :         if (r < 0)
    1093                 :          0 :                 return r;
    1094                 :            : 
    1095                 :          0 :         r = table_set_align_percent(table, cell, 100);
    1096         [ #  # ]:          0 :         if (r < 0)
    1097                 :          0 :                 return r;
    1098                 :            : 
    1099         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1100                 :          0 :         r = table_set_ellipsize_percent(table, cell, 100);
    1101         [ #  # ]:          0 :         if (r < 0)
    1102                 :          0 :                 return r;
    1103                 :            : 
    1104                 :          0 :         r = table_set_sort(table, 0, SIZE_MAX);
    1105         [ #  # ]:          0 :         if (r < 0)
    1106                 :          0 :                 return r;
    1107                 :            : 
    1108                 :          0 :         r = table_set_reverse(table, 0, true);
    1109         [ #  # ]:          0 :         if (r < 0)
    1110                 :          0 :                 return r;
    1111                 :            : 
    1112         [ #  # ]:          0 :         for (u = times; u->has_data; u++) {
    1113         [ #  # ]:          0 :                 if (u->time <= 0)
    1114                 :          0 :                         continue;
    1115                 :            : 
    1116                 :          0 :                 r = table_add_cell(table, NULL, TABLE_TIMESPAN_MSEC, &u->time);
    1117         [ #  # ]:          0 :                 if (r < 0)
    1118                 :          0 :                         return r;
    1119                 :            : 
    1120                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, u->name);
    1121         [ #  # ]:          0 :                 if (r < 0)
    1122                 :          0 :                         return r;
    1123                 :            :         }
    1124                 :            : 
    1125                 :          0 :         (void) pager_open(arg_pager_flags);
    1126                 :            : 
    1127                 :          0 :         return table_print(table, NULL);
    1128                 :            : }
    1129                 :            : 
    1130                 :          0 : static int analyze_time(int argc, char *argv[], void *userdata) {
    1131                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1132                 :          0 :         _cleanup_free_ char *buf = NULL;
    1133                 :            :         int r;
    1134                 :            : 
    1135                 :          0 :         r = acquire_bus(&bus, NULL);
    1136         [ #  # ]:          0 :         if (r < 0)
    1137         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1138                 :            : 
    1139                 :          0 :         r = pretty_boot_time(bus, &buf);
    1140         [ #  # ]:          0 :         if (r < 0)
    1141                 :          0 :                 return r;
    1142                 :            : 
    1143                 :          0 :         puts(buf);
    1144                 :          0 :         return 0;
    1145                 :            : }
    1146                 :            : 
    1147                 :          0 : static int graph_one_property(
    1148                 :            :                 sd_bus *bus,
    1149                 :            :                 const UnitInfo *u,
    1150                 :            :                 const char *prop,
    1151                 :            :                 const char *color,
    1152                 :            :                 char *patterns[],
    1153                 :            :                 char *from_patterns[],
    1154                 :            :                 char *to_patterns[]) {
    1155                 :            : 
    1156                 :          0 :         _cleanup_strv_free_ char **units = NULL;
    1157                 :            :         char **unit;
    1158                 :            :         int r;
    1159                 :            :         bool match_patterns;
    1160                 :            : 
    1161         [ #  # ]:          0 :         assert(u);
    1162         [ #  # ]:          0 :         assert(prop);
    1163         [ #  # ]:          0 :         assert(color);
    1164                 :            : 
    1165                 :          0 :         match_patterns = strv_fnmatch(patterns, u->id, 0);
    1166                 :            : 
    1167   [ #  #  #  #  :          0 :         if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id, 0))
                   #  # ]
    1168                 :          0 :                 return 0;
    1169                 :            : 
    1170                 :          0 :         r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
    1171         [ #  # ]:          0 :         if (r < 0)
    1172                 :          0 :                 return r;
    1173                 :            : 
    1174   [ #  #  #  # ]:          0 :         STRV_FOREACH(unit, units) {
    1175                 :            :                 bool match_patterns2;
    1176                 :            : 
    1177                 :          0 :                 match_patterns2 = strv_fnmatch(patterns, *unit, 0);
    1178                 :            : 
    1179   [ #  #  #  #  :          0 :                 if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit, 0))
                   #  # ]
    1180                 :          0 :                         continue;
    1181                 :            : 
    1182   [ #  #  #  #  :          0 :                 if (!strv_isempty(patterns) && !match_patterns && !match_patterns2)
                   #  # ]
    1183                 :          0 :                         continue;
    1184                 :            : 
    1185                 :          0 :                 printf("\t\"%s\"->\"%s\" [color=\"%s\"];\n", u->id, *unit, color);
    1186                 :            :         }
    1187                 :            : 
    1188                 :          0 :         return 0;
    1189                 :            : }
    1190                 :            : 
    1191                 :          0 : static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *from_patterns[], char *to_patterns[]) {
    1192                 :            :         int r;
    1193                 :            : 
    1194         [ #  # ]:          0 :         assert(bus);
    1195         [ #  # ]:          0 :         assert(u);
    1196                 :            : 
    1197   [ #  #  #  # ]:          0 :         if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) {
    1198                 :          0 :                 r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns);
    1199         [ #  # ]:          0 :                 if (r < 0)
    1200                 :          0 :                         return r;
    1201                 :            :         }
    1202                 :            : 
    1203   [ #  #  #  # ]:          0 :         if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) {
    1204                 :          0 :                 r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns);
    1205         [ #  # ]:          0 :                 if (r < 0)
    1206                 :          0 :                         return r;
    1207                 :          0 :                 r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns);
    1208         [ #  # ]:          0 :                 if (r < 0)
    1209                 :          0 :                         return r;
    1210                 :          0 :                 r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
    1211         [ #  # ]:          0 :                 if (r < 0)
    1212                 :          0 :                         return r;
    1213                 :          0 :                 r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
    1214         [ #  # ]:          0 :                 if (r < 0)
    1215                 :          0 :                         return r;
    1216                 :            :         }
    1217                 :            : 
    1218                 :          0 :         return 0;
    1219                 :            : }
    1220                 :            : 
    1221                 :          0 : static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) {
    1222                 :          0 :         _cleanup_strv_free_ char **expanded_patterns = NULL;
    1223                 :            :         char **pattern;
    1224                 :            :         int r;
    1225                 :            : 
    1226   [ #  #  #  # ]:          0 :         STRV_FOREACH(pattern, patterns) {
    1227      [ #  #  # ]:          0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1228   [ #  #  #  #  :          0 :                 _cleanup_free_ char *unit = NULL, *unit_id = NULL;
                   #  # ]
    1229                 :            : 
    1230         [ #  # ]:          0 :                 if (strv_extend(&expanded_patterns, *pattern) < 0)
    1231                 :          0 :                         return log_oom();
    1232                 :            : 
    1233         [ #  # ]:          0 :                 if (string_is_glob(*pattern))
    1234                 :          0 :                         continue;
    1235                 :            : 
    1236                 :          0 :                 unit = unit_dbus_path_from_name(*pattern);
    1237         [ #  # ]:          0 :                 if (!unit)
    1238                 :          0 :                         return log_oom();
    1239                 :            : 
    1240                 :          0 :                 r = sd_bus_get_property_string(
    1241                 :            :                                 bus,
    1242                 :            :                                 "org.freedesktop.systemd1",
    1243                 :            :                                 unit,
    1244                 :            :                                 "org.freedesktop.systemd1.Unit",
    1245                 :            :                                 "Id",
    1246                 :            :                                 &error,
    1247                 :            :                                 &unit_id);
    1248         [ #  # ]:          0 :                 if (r < 0)
    1249         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
    1250                 :            : 
    1251         [ #  # ]:          0 :                 if (!streq(*pattern, unit_id)) {
    1252         [ #  # ]:          0 :                         if (strv_extend(&expanded_patterns, unit_id) < 0)
    1253                 :          0 :                                 return log_oom();
    1254                 :            :                 }
    1255                 :            :         }
    1256                 :            : 
    1257                 :          0 :         *ret = expanded_patterns;
    1258                 :          0 :         expanded_patterns = NULL; /* do not free */
    1259                 :            : 
    1260                 :          0 :         return 0;
    1261                 :            : }
    1262                 :            : 
    1263                 :          0 : static int dot(int argc, char *argv[], void *userdata) {
    1264                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
    1265                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1266                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1267                 :          0 :         _cleanup_strv_free_ char **expanded_patterns = NULL;
    1268                 :          0 :         _cleanup_strv_free_ char **expanded_from_patterns = NULL;
    1269                 :          0 :         _cleanup_strv_free_ char **expanded_to_patterns = NULL;
    1270                 :            :         int r;
    1271                 :            :         UnitInfo u;
    1272                 :            : 
    1273                 :          0 :         r = acquire_bus(&bus, NULL);
    1274         [ #  # ]:          0 :         if (r < 0)
    1275         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1276                 :            : 
    1277                 :          0 :         r = expand_patterns(bus, strv_skip(argv, 1), &expanded_patterns);
    1278         [ #  # ]:          0 :         if (r < 0)
    1279                 :          0 :                 return r;
    1280                 :            : 
    1281                 :          0 :         r = expand_patterns(bus, arg_dot_from_patterns, &expanded_from_patterns);
    1282         [ #  # ]:          0 :         if (r < 0)
    1283                 :          0 :                 return r;
    1284                 :            : 
    1285                 :          0 :         r = expand_patterns(bus, arg_dot_to_patterns, &expanded_to_patterns);
    1286         [ #  # ]:          0 :         if (r < 0)
    1287                 :          0 :                 return r;
    1288                 :            : 
    1289                 :          0 :         r = sd_bus_call_method(
    1290                 :            :                         bus,
    1291                 :            :                        "org.freedesktop.systemd1",
    1292                 :            :                        "/org/freedesktop/systemd1",
    1293                 :            :                        "org.freedesktop.systemd1.Manager",
    1294                 :            :                        "ListUnits",
    1295                 :            :                        &error,
    1296                 :            :                        &reply,
    1297                 :            :                        "");
    1298         [ #  # ]:          0 :         if (r < 0)
    1299         [ #  # ]:          0 :                 log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
    1300                 :            : 
    1301                 :          0 :         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
    1302         [ #  # ]:          0 :         if (r < 0)
    1303         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1304                 :            : 
    1305                 :          0 :         printf("digraph systemd {\n");
    1306                 :            : 
    1307         [ #  # ]:          0 :         while ((r = bus_parse_unit_info(reply, &u)) > 0) {
    1308                 :            : 
    1309                 :          0 :                 r = graph_one(bus, &u, expanded_patterns, expanded_from_patterns, expanded_to_patterns);
    1310         [ #  # ]:          0 :                 if (r < 0)
    1311                 :          0 :                         return r;
    1312                 :            :         }
    1313         [ #  # ]:          0 :         if (r < 0)
    1314         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1315                 :            : 
    1316                 :          0 :         printf("}\n");
    1317                 :            : 
    1318         [ #  # ]:          0 :         log_info("   Color legend: black     = Requires\n"
    1319                 :            :                  "                 dark blue = Requisite\n"
    1320                 :            :                  "                 dark grey = Wants\n"
    1321                 :            :                  "                 red       = Conflicts\n"
    1322                 :            :                  "                 green     = After\n");
    1323                 :            : 
    1324         [ #  # ]:          0 :         if (on_tty())
    1325         [ #  # ]:          0 :                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
    1326                 :            :                            "-- Try a shell pipeline like 'systemd-analyze dot | dot -Tsvg > systemd.svg'!\n");
    1327                 :            : 
    1328                 :          0 :         return 0;
    1329                 :            : }
    1330                 :            : 
    1331                 :          0 : static int dump_fallback(sd_bus *bus) {
    1332                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1333                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
    1334                 :          0 :         const char *text = NULL;
    1335                 :            :         int r;
    1336                 :            : 
    1337         [ #  # ]:          0 :         assert(bus);
    1338                 :            : 
    1339                 :          0 :         r = sd_bus_call_method(
    1340                 :            :                         bus,
    1341                 :            :                         "org.freedesktop.systemd1",
    1342                 :            :                         "/org/freedesktop/systemd1",
    1343                 :            :                         "org.freedesktop.systemd1.Manager",
    1344                 :            :                         "Dump",
    1345                 :            :                         &error,
    1346                 :            :                         &reply,
    1347                 :            :                         NULL);
    1348         [ #  # ]:          0 :         if (r < 0)
    1349         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to issue method call Dump: %s", bus_error_message(&error, r));
    1350                 :            : 
    1351                 :          0 :         r = sd_bus_message_read(reply, "s", &text);
    1352         [ #  # ]:          0 :         if (r < 0)
    1353         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1354                 :            : 
    1355                 :          0 :         fputs(text, stdout);
    1356                 :          0 :         return 0;
    1357                 :            : }
    1358                 :            : 
    1359                 :          0 : static int dump(int argc, char *argv[], void *userdata) {
    1360                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1361                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
    1362                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1363                 :          0 :         int fd = -1;
    1364                 :            :         int r;
    1365                 :            : 
    1366                 :          0 :         r = acquire_bus(&bus, NULL);
    1367         [ #  # ]:          0 :         if (r < 0)
    1368         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1369                 :            : 
    1370                 :          0 :         (void) pager_open(arg_pager_flags);
    1371                 :            : 
    1372         [ #  # ]:          0 :         if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD))
    1373                 :          0 :                 return dump_fallback(bus);
    1374                 :            : 
    1375                 :          0 :         r = sd_bus_call_method(
    1376                 :            :                         bus,
    1377                 :            :                         "org.freedesktop.systemd1",
    1378                 :            :                         "/org/freedesktop/systemd1",
    1379                 :            :                         "org.freedesktop.systemd1.Manager",
    1380                 :            :                         "DumpByFileDescriptor",
    1381                 :            :                         &error,
    1382                 :            :                         &reply,
    1383                 :            :                         NULL);
    1384         [ #  # ]:          0 :         if (r < 0) {
    1385                 :            :                 /* fall back to Dump if DumpByFileDescriptor is not supported */
    1386   [ #  #  #  # ]:          0 :                 if (!IN_SET(r, -EACCES, -EBADR))
    1387         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to issue method call DumpByFileDescriptor: %s",
    1388                 :            :                                                bus_error_message(&error, r));
    1389                 :            : 
    1390                 :          0 :                 return dump_fallback(bus);
    1391                 :            :         }
    1392                 :            : 
    1393                 :          0 :         r = sd_bus_message_read(reply, "h", &fd);
    1394         [ #  # ]:          0 :         if (r < 0)
    1395         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1396                 :            : 
    1397                 :          0 :         fflush(stdout);
    1398                 :          0 :         return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
    1399                 :            : }
    1400                 :            : 
    1401                 :          0 : static int cat_config(int argc, char *argv[], void *userdata) {
    1402                 :            :         char **arg, **list;
    1403                 :            :         int r;
    1404                 :            : 
    1405                 :          0 :         (void) pager_open(arg_pager_flags);
    1406                 :            : 
    1407                 :          0 :         list = strv_skip(argv, 1);
    1408   [ #  #  #  # ]:          0 :         STRV_FOREACH(arg, list) {
    1409                 :          0 :                 const char *t = NULL;
    1410                 :            : 
    1411         [ #  # ]:          0 :                 if (arg != list)
    1412                 :          0 :                         print_separator();
    1413                 :            : 
    1414         [ #  # ]:          0 :                 if (path_is_absolute(*arg)) {
    1415                 :            :                         const char *dir;
    1416                 :            : 
    1417   [ #  #  #  # ]:          0 :                         NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) {
    1418                 :          0 :                                 t = path_startswith(*arg, dir);
    1419         [ #  # ]:          0 :                                 if (t)
    1420                 :          0 :                                         break;
    1421                 :            :                         }
    1422                 :            : 
    1423         [ #  # ]:          0 :                         if (!t)
    1424         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1425                 :            :                                                        "Path %s does not start with any known prefix.", *arg);
    1426                 :            :                 } else
    1427                 :          0 :                         t = *arg;
    1428                 :            : 
    1429                 :          0 :                 r = conf_files_cat(arg_root, t);
    1430         [ #  # ]:          0 :                 if (r < 0)
    1431                 :          0 :                         return r;
    1432                 :            :         }
    1433                 :            : 
    1434                 :          0 :         return 0;
    1435                 :            : }
    1436                 :            : 
    1437                 :          0 : static int set_log_level(int argc, char *argv[], void *userdata) {
    1438                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1439                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1440                 :            :         int r;
    1441                 :            : 
    1442         [ #  # ]:          0 :         assert(argc == 2);
    1443         [ #  # ]:          0 :         assert(argv);
    1444                 :            : 
    1445                 :          0 :         r = acquire_bus(&bus, NULL);
    1446         [ #  # ]:          0 :         if (r < 0)
    1447         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1448                 :            : 
    1449                 :          0 :         r = sd_bus_set_property(
    1450                 :            :                         bus,
    1451                 :            :                         "org.freedesktop.systemd1",
    1452                 :            :                         "/org/freedesktop/systemd1",
    1453                 :            :                         "org.freedesktop.systemd1.Manager",
    1454                 :            :                         "LogLevel",
    1455                 :            :                         &error,
    1456                 :            :                         "s",
    1457                 :          0 :                         argv[1]);
    1458         [ #  # ]:          0 :         if (r < 0)
    1459         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
    1460                 :            : 
    1461                 :          0 :         return 0;
    1462                 :            : }
    1463                 :            : 
    1464                 :          0 : static int get_log_level(int argc, char *argv[], void *userdata) {
    1465                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1466                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1467                 :          0 :         _cleanup_free_ char *level = NULL;
    1468                 :            :         int r;
    1469                 :            : 
    1470                 :          0 :         r = acquire_bus(&bus, NULL);
    1471         [ #  # ]:          0 :         if (r < 0)
    1472         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1473                 :            : 
    1474                 :          0 :         r = sd_bus_get_property_string(
    1475                 :            :                         bus,
    1476                 :            :                         "org.freedesktop.systemd1",
    1477                 :            :                         "/org/freedesktop/systemd1",
    1478                 :            :                         "org.freedesktop.systemd1.Manager",
    1479                 :            :                         "LogLevel",
    1480                 :            :                         &error,
    1481                 :            :                         &level);
    1482         [ #  # ]:          0 :         if (r < 0)
    1483         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get log level: %s", bus_error_message(&error, r));
    1484                 :            : 
    1485                 :          0 :         puts(level);
    1486                 :          0 :         return 0;
    1487                 :            : }
    1488                 :            : 
    1489                 :          0 : static int get_or_set_log_level(int argc, char *argv[], void *userdata) {
    1490         [ #  # ]:          0 :         return (argc == 1) ? get_log_level(argc, argv, userdata) : set_log_level(argc, argv, userdata);
    1491                 :            : }
    1492                 :            : 
    1493                 :          0 : static int set_log_target(int argc, char *argv[], void *userdata) {
    1494                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1495                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1496                 :            :         int r;
    1497                 :            : 
    1498         [ #  # ]:          0 :         assert(argc == 2);
    1499         [ #  # ]:          0 :         assert(argv);
    1500                 :            : 
    1501                 :          0 :         r = acquire_bus(&bus, NULL);
    1502         [ #  # ]:          0 :         if (r < 0)
    1503         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1504                 :            : 
    1505                 :          0 :         r = sd_bus_set_property(
    1506                 :            :                         bus,
    1507                 :            :                         "org.freedesktop.systemd1",
    1508                 :            :                         "/org/freedesktop/systemd1",
    1509                 :            :                         "org.freedesktop.systemd1.Manager",
    1510                 :            :                         "LogTarget",
    1511                 :            :                         &error,
    1512                 :            :                         "s",
    1513                 :          0 :                         argv[1]);
    1514         [ #  # ]:          0 :         if (r < 0)
    1515         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
    1516                 :            : 
    1517                 :          0 :         return 0;
    1518                 :            : }
    1519                 :            : 
    1520                 :          0 : static int get_log_target(int argc, char *argv[], void *userdata) {
    1521                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1522                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1523                 :          0 :         _cleanup_free_ char *target = NULL;
    1524                 :            :         int r;
    1525                 :            : 
    1526                 :          0 :         r = acquire_bus(&bus, NULL);
    1527         [ #  # ]:          0 :         if (r < 0)
    1528         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1529                 :            : 
    1530                 :          0 :         r = sd_bus_get_property_string(
    1531                 :            :                         bus,
    1532                 :            :                         "org.freedesktop.systemd1",
    1533                 :            :                         "/org/freedesktop/systemd1",
    1534                 :            :                         "org.freedesktop.systemd1.Manager",
    1535                 :            :                         "LogTarget",
    1536                 :            :                         &error,
    1537                 :            :                         &target);
    1538         [ #  # ]:          0 :         if (r < 0)
    1539         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get log target: %s", bus_error_message(&error, r));
    1540                 :            : 
    1541                 :          0 :         puts(target);
    1542                 :          0 :         return 0;
    1543                 :            : }
    1544                 :            : 
    1545                 :          0 : static int get_or_set_log_target(int argc, char *argv[], void *userdata) {
    1546         [ #  # ]:          0 :         return (argc == 1) ? get_log_target(argc, argv, userdata) : set_log_target(argc, argv, userdata);
    1547                 :            : }
    1548                 :            : 
    1549                 :          0 : static bool strv_fnmatch_strv_or_empty(char* const* patterns, char **strv, int flags) {
    1550                 :            :         char **s;
    1551   [ #  #  #  # ]:          0 :         STRV_FOREACH(s, strv)
    1552         [ #  # ]:          0 :                 if (strv_fnmatch_or_empty(patterns, *s, flags))
    1553                 :          0 :                         return true;
    1554                 :            : 
    1555                 :          0 :         return false;
    1556                 :            : }
    1557                 :            : 
    1558                 :          0 : static int do_unit_files(int argc, char *argv[], void *userdata) {
    1559                 :          0 :         _cleanup_(lookup_paths_free) LookupPaths lp = {};
    1560                 :          0 :         _cleanup_hashmap_free_ Hashmap *unit_ids = NULL;
    1561                 :          0 :         _cleanup_hashmap_free_ Hashmap *unit_names = NULL;
    1562                 :          0 :         char **patterns = strv_skip(argv, 1);
    1563                 :            :         Iterator i;
    1564                 :            :         const char *k, *dst;
    1565                 :            :         char **v;
    1566                 :            :         int r;
    1567                 :            : 
    1568                 :          0 :         r = lookup_paths_init(&lp, arg_scope, 0, NULL);
    1569         [ #  # ]:          0 :         if (r < 0)
    1570         [ #  # ]:          0 :                 return log_error_errno(r, "lookup_paths_init() failed: %m");
    1571                 :            : 
    1572                 :          0 :         r = unit_file_build_name_map(&lp, NULL, &unit_ids, &unit_names, NULL);
    1573         [ #  # ]:          0 :         if (r < 0)
    1574         [ #  # ]:          0 :                 return log_error_errno(r, "unit_file_build_name_map() failed: %m");
    1575                 :            : 
    1576         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(dst, k, unit_ids, i) {
    1577         [ #  # ]:          0 :                 if (!strv_fnmatch_or_empty(patterns, k, FNM_NOESCAPE) &&
    1578         [ #  # ]:          0 :                     !strv_fnmatch_or_empty(patterns, dst, FNM_NOESCAPE))
    1579                 :          0 :                         continue;
    1580                 :            : 
    1581                 :          0 :                 printf("ids: %s → %s\n", k, dst);
    1582                 :            :         }
    1583                 :            : 
    1584         [ #  # ]:          0 :         HASHMAP_FOREACH_KEY(v, k, unit_names, i) {
    1585         [ #  # ]:          0 :                 if (!strv_fnmatch_or_empty(patterns, k, FNM_NOESCAPE) &&
    1586         [ #  # ]:          0 :                     !strv_fnmatch_strv_or_empty(patterns, v, FNM_NOESCAPE))
    1587                 :          0 :                         continue;
    1588                 :            : 
    1589                 :          0 :                 _cleanup_free_ char *j = strv_join(v, ", ");
    1590                 :          0 :                 printf("aliases: %s ← %s\n", k, j);
    1591                 :            :         }
    1592                 :            : 
    1593                 :          0 :         return 0;
    1594                 :            : }
    1595                 :            : 
    1596                 :          0 : static int dump_unit_paths(int argc, char *argv[], void *userdata) {
    1597                 :          0 :         _cleanup_(lookup_paths_free) LookupPaths paths = {};
    1598                 :            :         int r;
    1599                 :            :         char **p;
    1600                 :            : 
    1601                 :          0 :         r = lookup_paths_init(&paths, arg_scope, 0, NULL);
    1602         [ #  # ]:          0 :         if (r < 0)
    1603         [ #  # ]:          0 :                 return log_error_errno(r, "lookup_paths_init() failed: %m");
    1604                 :            : 
    1605   [ #  #  #  # ]:          0 :         STRV_FOREACH(p, paths.search_path)
    1606                 :          0 :                 puts(*p);
    1607                 :            : 
    1608                 :          0 :         return 0;
    1609                 :            : }
    1610                 :            : 
    1611                 :          0 : static int dump_exit_status(int argc, char *argv[], void *userdata) {
    1612                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1613                 :            :         int r;
    1614                 :            : 
    1615                 :          0 :         table = table_new("name", "status", "class");
    1616         [ #  # ]:          0 :         if (!table)
    1617                 :          0 :                 return log_oom();
    1618                 :            : 
    1619                 :          0 :         r = table_set_align_percent(table, table_get_cell(table, 0, 1), 100);
    1620         [ #  # ]:          0 :         if (r < 0)
    1621         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to right-align status: %m");
    1622                 :            : 
    1623         [ #  # ]:          0 :         if (strv_isempty(strv_skip(argv, 1)))
    1624         [ #  # ]:          0 :                 for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++) {
    1625         [ #  # ]:          0 :                         if (!exit_status_mappings[i].name)
    1626                 :          0 :                                 continue;
    1627                 :            : 
    1628                 :          0 :                         r = table_add_many(table,
    1629                 :            :                                            TABLE_STRING, exit_status_mappings[i].name,
    1630                 :            :                                            TABLE_INT, (int) i,
    1631                 :            :                                            TABLE_STRING, exit_status_class(i));
    1632         [ #  # ]:          0 :                         if (r < 0)
    1633                 :          0 :                                 return r;
    1634                 :            :                 }
    1635                 :            :         else
    1636         [ #  # ]:          0 :                 for (int i = 1; i < argc; i++) {
    1637                 :            :                         int status;
    1638                 :            : 
    1639                 :          0 :                         status = exit_status_from_string(argv[i]);
    1640         [ #  # ]:          0 :                         if (status < 0)
    1641         [ #  # ]:          0 :                                 return log_error_errno(r, "Invalid exit status \"%s\": %m", argv[i]);
    1642                 :            : 
    1643   [ #  #  #  # ]:          0 :                         assert(status >= 0 && (size_t) status < ELEMENTSOF(exit_status_mappings));
    1644   [ #  #  #  # ]:          0 :                         r = table_add_many(table,
    1645                 :            :                                            TABLE_STRING, exit_status_mappings[status].name ?: "-",
    1646                 :            :                                            TABLE_INT, status,
    1647                 :            :                                            TABLE_STRING, exit_status_class(status) ?: "-");
    1648         [ #  # ]:          0 :                         if (r < 0)
    1649                 :          0 :                                 return r;
    1650                 :            :                 }
    1651                 :            : 
    1652                 :          0 :         (void) pager_open(arg_pager_flags);
    1653                 :            : 
    1654                 :          0 :         return table_print(table, NULL);
    1655                 :            : }
    1656                 :            : 
    1657                 :            : #if HAVE_SECCOMP
    1658                 :            : 
    1659                 :          0 : static int load_kernel_syscalls(Set **ret) {
    1660                 :          0 :         _cleanup_(set_free_freep) Set *syscalls = NULL;
    1661                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
    1662                 :            :         int r;
    1663                 :            : 
    1664                 :            :         /* Let's read the available system calls from the list of available tracing events. Slightly dirty,
    1665                 :            :          * but good enough for analysis purposes. */
    1666                 :            : 
    1667                 :          0 :         f = fopen("/sys/kernel/tracing/available_events", "re");
    1668         [ #  # ]:          0 :         if (!f) {
    1669                 :            :                 /* We tried the non-debugfs mount point and that didn't work. If it wasn't mounted, maybe the
    1670                 :            :                  * old debugfs mount point works? */
    1671                 :          0 :                 f = fopen("/sys/kernel/debug/tracing/available_events", "re");
    1672         [ #  # ]:          0 :                 if (!f)
    1673   [ #  #  #  #  :          0 :                         return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno,
                   #  # ]
    1674                 :            :                                               "Can't read open tracefs' available_events file: %m");
    1675                 :            :         }
    1676                 :            : 
    1677                 :          0 :         for (;;) {
    1678   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *line = NULL;
    1679                 :            :                 const char *e;
    1680                 :            : 
    1681                 :          0 :                 r = read_line(f, LONG_LINE_MAX, &line);
    1682         [ #  # ]:          0 :                 if (r < 0)
    1683         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to read system call list: %m");
    1684         [ #  # ]:          0 :                 if (r == 0)
    1685                 :          0 :                         break;
    1686                 :            : 
    1687                 :          0 :                 e = startswith(line, "syscalls:sys_enter_");
    1688         [ #  # ]:          0 :                 if (!e)
    1689                 :          0 :                         continue;
    1690                 :            : 
    1691                 :            :                 /* These are named differently inside the kernel than their external name for historical
    1692                 :            :                  * reasons. Let's hide them here. */
    1693         [ #  # ]:          0 :                 if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
    1694                 :          0 :                         continue;
    1695                 :            : 
    1696                 :          0 :                 r = set_ensure_allocated(&syscalls, &string_hash_ops);
    1697         [ #  # ]:          0 :                 if (r < 0)
    1698                 :          0 :                         return log_oom();
    1699                 :            : 
    1700                 :          0 :                 r = set_put_strdup(syscalls, e);
    1701         [ #  # ]:          0 :                 if (r < 0)
    1702         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to add system call to list: %m");
    1703                 :            :         }
    1704                 :            : 
    1705                 :          0 :         *ret = TAKE_PTR(syscalls);
    1706                 :          0 :         return 0;
    1707                 :            : }
    1708                 :            : 
    1709                 :          0 : static void kernel_syscalls_remove(Set *s, const SyscallFilterSet *set) {
    1710                 :            :         const char *syscall;
    1711                 :            : 
    1712   [ #  #  #  # ]:          0 :         NULSTR_FOREACH(syscall, set->value) {
    1713         [ #  # ]:          0 :                 if (syscall[0] == '@')
    1714                 :          0 :                         continue;
    1715                 :            : 
    1716                 :          0 :                 (void) set_remove(s, syscall);
    1717                 :            :         }
    1718                 :          0 : }
    1719                 :            : 
    1720                 :          0 : static void dump_syscall_filter(const SyscallFilterSet *set) {
    1721                 :            :         const char *syscall;
    1722                 :            : 
    1723                 :          0 :         printf("%s%s%s\n"
    1724                 :            :                "    # %s\n",
    1725                 :            :                ansi_highlight(),
    1726                 :            :                set->name,
    1727                 :            :                ansi_normal(),
    1728                 :            :                set->help);
    1729                 :            : 
    1730   [ #  #  #  # ]:          0 :         NULSTR_FOREACH(syscall, set->value)
    1731         [ #  # ]:          0 :                 printf("    %s%s%s\n", syscall[0] == '@' ? ansi_underline() : "", syscall, ansi_normal());
    1732                 :          0 : }
    1733                 :            : 
    1734                 :          0 : static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
    1735                 :          0 :         bool first = true;
    1736                 :            : 
    1737                 :          0 :         (void) pager_open(arg_pager_flags);
    1738                 :            : 
    1739         [ #  # ]:          0 :         if (strv_isempty(strv_skip(argv, 1))) {
    1740                 :          0 :                 _cleanup_(set_free_freep) Set *kernel = NULL;
    1741                 :            :                 int i, k;
    1742                 :            : 
    1743                 :          0 :                 k = load_kernel_syscalls(&kernel);
    1744                 :            : 
    1745         [ #  # ]:          0 :                 for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
    1746                 :          0 :                         const SyscallFilterSet *set = syscall_filter_sets + i;
    1747         [ #  # ]:          0 :                         if (!first)
    1748                 :          0 :                                 puts("");
    1749                 :            : 
    1750                 :          0 :                         dump_syscall_filter(set);
    1751                 :          0 :                         kernel_syscalls_remove(kernel, set);
    1752                 :          0 :                         first = false;
    1753                 :            :                 }
    1754                 :            : 
    1755         [ #  # ]:          0 :                 if (k < 0) {
    1756                 :          0 :                         fputc('\n', stdout);
    1757                 :          0 :                         fflush(stdout);
    1758         [ #  # ]:          0 :                         log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m");
    1759         [ #  # ]:          0 :                 } else if (!set_isempty(kernel)) {
    1760                 :            :                         const char *syscall;
    1761                 :            :                         Iterator j;
    1762                 :            : 
    1763                 :          0 :                         printf("\n"
    1764                 :            :                                "# %sUnlisted System Calls%s (supported by the local kernel, but not included in any of the groups listed above):\n",
    1765                 :            :                                ansi_highlight(), ansi_normal());
    1766                 :            : 
    1767         [ #  # ]:          0 :                         SET_FOREACH(syscall, kernel, j)
    1768                 :          0 :                                 printf("#   %s\n", syscall);
    1769                 :            :                 }
    1770                 :            :         } else {
    1771                 :            :                 char **name;
    1772                 :            : 
    1773   [ #  #  #  # ]:          0 :                 STRV_FOREACH(name, strv_skip(argv, 1)) {
    1774                 :            :                         const SyscallFilterSet *set;
    1775                 :            : 
    1776         [ #  # ]:          0 :                         if (!first)
    1777                 :          0 :                                 puts("");
    1778                 :            : 
    1779                 :          0 :                         set = syscall_filter_set_find(*name);
    1780         [ #  # ]:          0 :                         if (!set) {
    1781                 :            :                                 /* make sure the error appears below normal output */
    1782                 :          0 :                                 fflush(stdout);
    1783                 :            : 
    1784         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
    1785                 :            :                                                        "Filter set \"%s\" not found.", *name);
    1786                 :            :                         }
    1787                 :            : 
    1788                 :          0 :                         dump_syscall_filter(set);
    1789                 :          0 :                         first = false;
    1790                 :            :                 }
    1791                 :            :         }
    1792                 :            : 
    1793                 :          0 :         return 0;
    1794                 :            : }
    1795                 :            : 
    1796                 :            : #else
    1797                 :            : static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
    1798                 :            :         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not compiled with syscall filters, sorry.");
    1799                 :            : }
    1800                 :            : #endif
    1801                 :            : 
    1802                 :          0 : static void parsing_hint(const char *p, bool calendar, bool timestamp, bool timespan) {
    1803   [ #  #  #  # ]:          0 :         if (calendar && calendar_spec_from_string(p, NULL) >= 0)
    1804         [ #  # ]:          0 :                 log_notice("Hint: this expression is a valid calendar specification. "
    1805                 :            :                            "Use 'systemd-analyze calendar \"%s\"' instead?", p);
    1806   [ #  #  #  # ]:          0 :         if (timestamp && parse_timestamp(p, NULL) >= 0)
    1807         [ #  # ]:          0 :                 log_notice("Hint: this expression is a valid timestamp. "
    1808                 :            :                            "Use 'systemd-analyze timestamp \"%s\"' instead?", p);
    1809   [ #  #  #  # ]:          0 :         if (timespan && parse_time(p, NULL, USEC_PER_SEC) >= 0)
    1810         [ #  # ]:          0 :                 log_notice("Hint: this expression is a valid timespan. "
    1811                 :            :                            "Use 'systemd-analyze timespan \"%s\"' instead?", p);
    1812                 :          0 : }
    1813                 :            : 
    1814                 :          0 : static int dump_timespan(int argc, char *argv[], void *userdata) {
    1815                 :            :         char **input_timespan;
    1816                 :            : 
    1817   [ #  #  #  # ]:          0 :         STRV_FOREACH(input_timespan, strv_skip(argv, 1)) {
    1818         [ #  # ]:          0 :                 _cleanup_(table_unrefp) Table *table = NULL;
    1819                 :            :                 usec_t output_usecs;
    1820                 :            :                 TableCell *cell;
    1821                 :            :                 int r;
    1822                 :            : 
    1823                 :          0 :                 r = parse_time(*input_timespan, &output_usecs, USEC_PER_SEC);
    1824         [ #  # ]:          0 :                 if (r < 0) {
    1825         [ #  # ]:          0 :                         log_error_errno(r, "Failed to parse time span '%s': %m", *input_timespan);
    1826                 :          0 :                         parsing_hint(*input_timespan, true, true, false);
    1827                 :          0 :                         return r;
    1828                 :            :                 }
    1829                 :            : 
    1830                 :          0 :                 table = table_new("name", "value");
    1831         [ #  # ]:          0 :                 if (!table)
    1832                 :          0 :                         return log_oom();
    1833                 :            : 
    1834                 :          0 :                 table_set_header(table, false);
    1835                 :            : 
    1836         [ #  # ]:          0 :                 assert_se(cell = table_get_cell(table, 0, 0));
    1837                 :          0 :                 r = table_set_ellipsize_percent(table, cell, 100);
    1838         [ #  # ]:          0 :                 if (r < 0)
    1839                 :          0 :                         return r;
    1840                 :            : 
    1841                 :          0 :                 r = table_set_align_percent(table, cell, 100);
    1842         [ #  # ]:          0 :                 if (r < 0)
    1843                 :          0 :                         return r;
    1844                 :            : 
    1845         [ #  # ]:          0 :                 assert_se(cell = table_get_cell(table, 0, 1));
    1846                 :          0 :                 r = table_set_ellipsize_percent(table, cell, 100);
    1847         [ #  # ]:          0 :                 if (r < 0)
    1848                 :          0 :                         return r;
    1849                 :            : 
    1850                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, "Original:");
    1851         [ #  # ]:          0 :                 if (r < 0)
    1852                 :          0 :                         return r;
    1853                 :            : 
    1854                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, *input_timespan);
    1855         [ #  # ]:          0 :                 if (r < 0)
    1856                 :          0 :                         return r;
    1857                 :            : 
    1858                 :          0 :                 r = table_add_cell_stringf(table, NULL, "%ss:", special_glyph(SPECIAL_GLYPH_MU));
    1859         [ #  # ]:          0 :                 if (r < 0)
    1860                 :          0 :                         return r;
    1861                 :            : 
    1862                 :          0 :                 r = table_add_cell(table, NULL, TABLE_UINT64, &output_usecs);
    1863         [ #  # ]:          0 :                 if (r < 0)
    1864                 :          0 :                         return r;
    1865                 :            : 
    1866                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, "Human:");
    1867         [ #  # ]:          0 :                 if (r < 0)
    1868                 :          0 :                         return r;
    1869                 :            : 
    1870                 :          0 :                 r = table_add_cell(table, &cell, TABLE_TIMESPAN, &output_usecs);
    1871         [ #  # ]:          0 :                 if (r < 0)
    1872                 :          0 :                         return r;
    1873                 :            : 
    1874                 :          0 :                 r = table_set_color(table, cell, ansi_highlight());
    1875         [ #  # ]:          0 :                 if (r < 0)
    1876                 :          0 :                         return r;
    1877                 :            : 
    1878                 :          0 :                 r = table_print(table, NULL);
    1879         [ #  # ]:          0 :                 if (r < 0)
    1880                 :          0 :                         return r;
    1881                 :            : 
    1882         [ #  # ]:          0 :                 if (input_timespan[1])
    1883                 :          0 :                         putchar('\n');
    1884                 :            :         }
    1885                 :            : 
    1886                 :          0 :         return EXIT_SUCCESS;
    1887                 :            : }
    1888                 :            : 
    1889                 :          0 : static int test_timestamp_one(const char *p) {
    1890                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1891                 :            :         TableCell *cell;
    1892                 :            :         usec_t usec;
    1893                 :            :         int r;
    1894                 :            : 
    1895                 :          0 :         r = parse_timestamp(p, &usec);
    1896         [ #  # ]:          0 :         if (r < 0) {
    1897         [ #  # ]:          0 :                 log_error_errno(r, "Failed to parse \"%s\": %m", p);
    1898                 :          0 :                 parsing_hint(p, true, false, true);
    1899                 :          0 :                 return r;
    1900                 :            :         }
    1901                 :            : 
    1902                 :          0 :         table = table_new("name", "value");
    1903         [ #  # ]:          0 :         if (!table)
    1904                 :          0 :                 return log_oom();
    1905                 :            : 
    1906                 :          0 :         table_set_header(table, false);
    1907                 :            : 
    1908         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1909                 :          0 :         r = table_set_ellipsize_percent(table, cell, 100);
    1910         [ #  # ]:          0 :         if (r < 0)
    1911                 :          0 :                 return r;
    1912                 :            : 
    1913                 :          0 :         r = table_set_align_percent(table, cell, 100);
    1914         [ #  # ]:          0 :         if (r < 0)
    1915                 :          0 :                 return r;
    1916                 :            : 
    1917         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1918                 :          0 :         r = table_set_ellipsize_percent(table, cell, 100);
    1919         [ #  # ]:          0 :         if (r < 0)
    1920                 :          0 :                 return r;
    1921                 :            : 
    1922                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, "Original form:");
    1923         [ #  # ]:          0 :         if (r < 0)
    1924                 :          0 :                 return r;
    1925                 :            : 
    1926                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, p);
    1927         [ #  # ]:          0 :         if (r < 0)
    1928                 :          0 :                 return r;
    1929                 :            : 
    1930                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, "Normalized form:");
    1931         [ #  # ]:          0 :         if (r < 0)
    1932                 :          0 :                 return r;
    1933                 :            : 
    1934                 :          0 :         r = table_add_cell(table, &cell, TABLE_TIMESTAMP, &usec);
    1935         [ #  # ]:          0 :         if (r < 0)
    1936                 :          0 :                 return r;
    1937                 :            : 
    1938                 :          0 :         r = table_set_color(table, cell, ansi_highlight_blue());
    1939         [ #  # ]:          0 :         if (r < 0)
    1940                 :          0 :                 return r;
    1941                 :            : 
    1942         [ #  # ]:          0 :         if (!in_utc_timezone()) {
    1943                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, "(in UTC):");
    1944         [ #  # ]:          0 :                 if (r < 0)
    1945                 :          0 :                         return r;
    1946                 :            : 
    1947                 :          0 :                 r = table_add_cell(table, &cell, TABLE_TIMESTAMP_UTC, &usec);
    1948         [ #  # ]:          0 :                 if (r < 0)
    1949                 :          0 :                         return r;
    1950                 :            :         }
    1951                 :            : 
    1952                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, "UNIX seconds:");
    1953         [ #  # ]:          0 :         if (r < 0)
    1954                 :          0 :                 return r;
    1955                 :            : 
    1956         [ #  # ]:          0 :         if (usec % USEC_PER_SEC == 0)
    1957                 :          0 :                 r = table_add_cell_stringf(table, &cell, "@%"PRI_USEC,
    1958                 :            :                                            usec / USEC_PER_SEC);
    1959                 :            :         else
    1960                 :          0 :                 r = table_add_cell_stringf(table, &cell, "@%"PRI_USEC".%06"PRI_USEC"",
    1961                 :            :                                            usec / USEC_PER_SEC,
    1962                 :            :                                            usec % USEC_PER_SEC);
    1963         [ #  # ]:          0 :         if (r < 0)
    1964                 :          0 :                 return r;
    1965                 :            : 
    1966                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, "From now:");
    1967         [ #  # ]:          0 :         if (r < 0)
    1968                 :          0 :                 return r;
    1969                 :            : 
    1970                 :          0 :         r = table_add_cell(table, &cell, TABLE_TIMESTAMP_RELATIVE, &usec);
    1971         [ #  # ]:          0 :         if (r < 0)
    1972                 :          0 :                 return r;
    1973                 :            : 
    1974                 :          0 :         return table_print(table, NULL);
    1975                 :            : }
    1976                 :            : 
    1977                 :          0 : static int test_timestamp(int argc, char *argv[], void *userdata) {
    1978                 :          0 :         int ret = 0, r;
    1979                 :            :         char **p;
    1980                 :            : 
    1981   [ #  #  #  # ]:          0 :         STRV_FOREACH(p, strv_skip(argv, 1)) {
    1982                 :          0 :                 r = test_timestamp_one(*p);
    1983   [ #  #  #  # ]:          0 :                 if (ret == 0 && r < 0)
    1984                 :          0 :                         ret = r;
    1985                 :            : 
    1986         [ #  # ]:          0 :                 if (*(p + 1))
    1987                 :          0 :                         putchar('\n');
    1988                 :            :         }
    1989                 :            : 
    1990                 :          0 :         return ret;
    1991                 :            : }
    1992                 :            : 
    1993                 :          0 : static int test_calendar_one(usec_t n, const char *p) {
    1994                 :          0 :         _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
    1995                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1996                 :          0 :         _cleanup_free_ char *t = NULL;
    1997                 :            :         TableCell *cell;
    1998                 :            :         int r;
    1999                 :            : 
    2000                 :          0 :         r = calendar_spec_from_string(p, &spec);
    2001         [ #  # ]:          0 :         if (r < 0) {
    2002         [ #  # ]:          0 :                 log_error_errno(r, "Failed to parse calendar specification '%s': %m", p);
    2003                 :          0 :                 parsing_hint(p, false, true, true);
    2004                 :          0 :                 return r;
    2005                 :            :         }
    2006                 :            : 
    2007                 :          0 :         r = calendar_spec_to_string(spec, &t);
    2008         [ #  # ]:          0 :         if (r < 0)
    2009         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to format calendar specification '%s': %m", p);
    2010                 :            : 
    2011                 :          0 :         table = table_new("name", "value");
    2012         [ #  # ]:          0 :         if (!table)
    2013                 :          0 :                 return log_oom();
    2014                 :            : 
    2015                 :          0 :         table_set_header(table, false);
    2016                 :            : 
    2017         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
    2018                 :          0 :         r = table_set_ellipsize_percent(table, cell, 100);
    2019         [ #  # ]:          0 :         if (r < 0)
    2020                 :          0 :                 return r;
    2021                 :            : 
    2022                 :          0 :         r = table_set_align_percent(table, cell, 100);
    2023         [ #  # ]:          0 :         if (r < 0)
    2024                 :          0 :                 return r;
    2025                 :            : 
    2026         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
    2027                 :          0 :         r = table_set_ellipsize_percent(table, cell, 100);
    2028         [ #  # ]:          0 :         if (r < 0)
    2029                 :          0 :                 return r;
    2030                 :            : 
    2031         [ #  # ]:          0 :         if (!streq(t, p)) {
    2032                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, "Original form:");
    2033         [ #  # ]:          0 :                 if (r < 0)
    2034                 :          0 :                         return r;
    2035                 :            : 
    2036                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, p);
    2037         [ #  # ]:          0 :                 if (r < 0)
    2038                 :          0 :                         return r;
    2039                 :            :         }
    2040                 :            : 
    2041                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, "Normalized form:");
    2042         [ #  # ]:          0 :         if (r < 0)
    2043                 :          0 :                 return r;
    2044                 :            : 
    2045                 :          0 :         r = table_add_cell(table, NULL, TABLE_STRING, t);
    2046         [ #  # ]:          0 :         if (r < 0)
    2047                 :          0 :                 return r;
    2048                 :            : 
    2049         [ #  # ]:          0 :         for (unsigned i = 0; i < arg_iterations; i++) {
    2050                 :            :                 usec_t next;
    2051                 :            : 
    2052                 :          0 :                 r = calendar_spec_next_usec(spec, n, &next);
    2053         [ #  # ]:          0 :                 if (r == -ENOENT) {
    2054         [ #  # ]:          0 :                         if (i == 0) {
    2055                 :          0 :                                 r = table_add_cell(table, NULL, TABLE_STRING, "Next elapse:");
    2056         [ #  # ]:          0 :                                 if (r < 0)
    2057                 :          0 :                                         return r;
    2058                 :            : 
    2059                 :          0 :                                 r = table_add_cell(table, &cell, TABLE_STRING, "never");
    2060         [ #  # ]:          0 :                                 if (r < 0)
    2061                 :          0 :                                         return r;
    2062                 :            : 
    2063                 :          0 :                                 r = table_set_color(table, cell, ansi_highlight_yellow());
    2064         [ #  # ]:          0 :                                 if (r < 0)
    2065                 :          0 :                                         return r;
    2066                 :            :                         }
    2067                 :          0 :                         break;
    2068                 :            :                 }
    2069         [ #  # ]:          0 :                 if (r < 0)
    2070         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to determine next elapse for '%s': %m", p);
    2071                 :            : 
    2072         [ #  # ]:          0 :                 if (i == 0) {
    2073                 :          0 :                         r = table_add_cell(table, NULL, TABLE_STRING, "Next elapse:");
    2074         [ #  # ]:          0 :                         if (r < 0)
    2075                 :          0 :                                 return r;
    2076                 :            : 
    2077                 :          0 :                         r = table_add_cell(table, &cell, TABLE_TIMESTAMP, &next);
    2078         [ #  # ]:          0 :                         if (r < 0)
    2079                 :          0 :                                 return r;
    2080                 :            : 
    2081                 :          0 :                         r = table_set_color(table, cell, ansi_highlight_blue());
    2082         [ #  # ]:          0 :                         if (r < 0)
    2083                 :          0 :                                 return r;
    2084                 :            :                 } else {
    2085         [ #  # ]:          0 :                         int k = DECIMAL_STR_WIDTH(i + 1);
    2086                 :            : 
    2087         [ #  # ]:          0 :                         if (k < 8)
    2088                 :          0 :                                 k = 8 - k;
    2089                 :            :                         else
    2090                 :          0 :                                 k = 0;
    2091                 :            : 
    2092                 :          0 :                         r = table_add_cell_stringf(table, NULL, "Iter. #%u:", i+1);
    2093         [ #  # ]:          0 :                         if (r < 0)
    2094                 :          0 :                                 return r;
    2095                 :            : 
    2096                 :          0 :                         r = table_add_cell(table, &cell, TABLE_TIMESTAMP, &next);
    2097         [ #  # ]:          0 :                         if (r < 0)
    2098                 :          0 :                                 return r;
    2099                 :            : 
    2100                 :          0 :                         r = table_set_color(table, cell, ansi_highlight_blue());
    2101         [ #  # ]:          0 :                         if (r < 0)
    2102                 :          0 :                                 return r;
    2103                 :            :                 }
    2104                 :            : 
    2105         [ #  # ]:          0 :                 if (!in_utc_timezone()) {
    2106                 :          0 :                         r = table_add_cell(table, NULL, TABLE_STRING, "(in UTC):");
    2107         [ #  # ]:          0 :                         if (r < 0)
    2108                 :          0 :                                 return r;
    2109                 :            : 
    2110                 :          0 :                         r = table_add_cell(table, NULL, TABLE_TIMESTAMP_UTC, &next);
    2111         [ #  # ]:          0 :                         if (r < 0)
    2112                 :          0 :                                 return r;
    2113                 :            :                 }
    2114                 :            : 
    2115                 :          0 :                 r = table_add_cell(table, NULL, TABLE_STRING, "From now:");
    2116         [ #  # ]:          0 :                 if (r < 0)
    2117                 :          0 :                         return r;
    2118                 :            : 
    2119                 :          0 :                 r = table_add_cell(table, NULL, TABLE_TIMESTAMP_RELATIVE, &next);
    2120         [ #  # ]:          0 :                 if (r < 0)
    2121                 :          0 :                         return r;
    2122                 :            : 
    2123                 :          0 :                 n = next;
    2124                 :            :         }
    2125                 :            : 
    2126                 :          0 :         return table_print(table, NULL);
    2127                 :            : }
    2128                 :            : 
    2129                 :          0 : static int test_calendar(int argc, char *argv[], void *userdata) {
    2130                 :          0 :         int ret = 0, r;
    2131                 :            :         char **p;
    2132                 :            :         usec_t n;
    2133                 :            : 
    2134                 :          0 :         n = now(CLOCK_REALTIME); /* We want to use the same "base" for all expressions */
    2135                 :            : 
    2136   [ #  #  #  # ]:          0 :         STRV_FOREACH(p, strv_skip(argv, 1)) {
    2137                 :          0 :                 r = test_calendar_one(n, *p);
    2138   [ #  #  #  # ]:          0 :                 if (ret == 0 && r < 0)
    2139                 :          0 :                         ret = r;
    2140                 :            : 
    2141         [ #  # ]:          0 :                 if (*(p + 1))
    2142                 :          0 :                         putchar('\n');
    2143                 :            :         }
    2144                 :            : 
    2145                 :          0 :         return ret;
    2146                 :            : }
    2147                 :            : 
    2148                 :          0 : static int service_watchdogs(int argc, char *argv[], void *userdata) {
    2149                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    2150                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    2151                 :            :         int b, r;
    2152                 :            : 
    2153   [ #  #  #  # ]:          0 :         assert(IN_SET(argc, 1, 2));
    2154         [ #  # ]:          0 :         assert(argv);
    2155                 :            : 
    2156                 :          0 :         r = acquire_bus(&bus, NULL);
    2157         [ #  # ]:          0 :         if (r < 0)
    2158         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    2159                 :            : 
    2160                 :            :         /* get ServiceWatchdogs */
    2161         [ #  # ]:          0 :         if (argc == 1) {
    2162                 :          0 :                 r = sd_bus_get_property_trivial(
    2163                 :            :                                 bus,
    2164                 :            :                                 "org.freedesktop.systemd1",
    2165                 :            :                                 "/org/freedesktop/systemd1",
    2166                 :            :                                 "org.freedesktop.systemd1.Manager",
    2167                 :            :                                 "ServiceWatchdogs",
    2168                 :            :                                 &error,
    2169                 :            :                                 'b',
    2170                 :            :                                 &b);
    2171         [ #  # ]:          0 :                 if (r < 0)
    2172         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
    2173                 :            : 
    2174                 :          0 :                 printf("%s\n", yes_no(!!b));
    2175                 :            : 
    2176                 :          0 :                 return 0;
    2177                 :            :         }
    2178                 :            : 
    2179                 :            :         /* set ServiceWatchdogs */
    2180                 :          0 :         b = parse_boolean(argv[1]);
    2181         [ #  # ]:          0 :         if (b < 0) {
    2182         [ #  # ]:          0 :                 log_error("Failed to parse service-watchdogs argument.");
    2183                 :          0 :                 return -EINVAL;
    2184                 :            :         }
    2185                 :            : 
    2186                 :          0 :         r = sd_bus_set_property(
    2187                 :            :                         bus,
    2188                 :            :                         "org.freedesktop.systemd1",
    2189                 :            :                         "/org/freedesktop/systemd1",
    2190                 :            :                         "org.freedesktop.systemd1.Manager",
    2191                 :            :                         "ServiceWatchdogs",
    2192                 :            :                         &error,
    2193                 :            :                         "b",
    2194                 :            :                         b);
    2195         [ #  # ]:          0 :         if (r < 0)
    2196         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
    2197                 :            : 
    2198                 :          0 :         return 0;
    2199                 :            : }
    2200                 :            : 
    2201                 :          0 : static int do_condition(int argc, char *argv[], void *userdata) {
    2202                 :          0 :         return verify_conditions(strv_skip(argv, 1), arg_scope);
    2203                 :            : }
    2204                 :            : 
    2205                 :          0 : static int do_verify(int argc, char *argv[], void *userdata) {
    2206                 :          0 :         return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators);
    2207                 :            : }
    2208                 :            : 
    2209                 :          0 : static int do_security(int argc, char *argv[], void *userdata) {
    2210                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    2211                 :            :         int r;
    2212                 :            : 
    2213                 :          0 :         r = acquire_bus(&bus, NULL);
    2214         [ #  # ]:          0 :         if (r < 0)
    2215         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    2216                 :            : 
    2217                 :          0 :         (void) pager_open(arg_pager_flags);
    2218                 :            : 
    2219                 :          0 :         return analyze_security(bus, strv_skip(argv, 1), 0);
    2220                 :            : }
    2221                 :            : 
    2222                 :         12 : static int help(int argc, char *argv[], void *userdata) {
    2223                 :         12 :         _cleanup_free_ char *link = NULL, *dot_link = NULL;
    2224                 :            :         int r;
    2225                 :            : 
    2226                 :         12 :         (void) pager_open(arg_pager_flags);
    2227                 :            : 
    2228                 :         12 :         r = terminal_urlify_man("systemd-analyze", "1", &link);
    2229         [ -  + ]:         12 :         if (r < 0)
    2230                 :          0 :                 return log_oom();
    2231                 :            : 
    2232                 :            :         /* Not using terminal_urlify_man() for this, since we don't want the "man page" text suffix in this case. */
    2233                 :         12 :         r = terminal_urlify("man:dot(1)", "dot(1)", &dot_link);
    2234         [ -  + ]:         12 :         if (r < 0)
    2235                 :          0 :                 return log_oom();
    2236                 :            : 
    2237                 :         12 :         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
    2238                 :            :                "Profile systemd, show unit dependencies, check unit files.\n\n"
    2239                 :            :                "  -h --help                Show this help\n"
    2240                 :            :                "     --version             Show package version\n"
    2241                 :            :                "     --no-pager            Do not pipe output into a pager\n"
    2242                 :            :                "     --system              Operate on system systemd instance\n"
    2243                 :            :                "     --user                Operate on user systemd instance\n"
    2244                 :            :                "     --global              Operate on global user configuration\n"
    2245                 :            :                "  -H --host=[USER@]HOST    Operate on remote host\n"
    2246                 :            :                "  -M --machine=CONTAINER   Operate on local container\n"
    2247                 :            :                "     --order               Show only order in the graph\n"
    2248                 :            :                "     --require             Show only requirement in the graph\n"
    2249                 :            :                "     --from-pattern=GLOB   Show only origins in the graph\n"
    2250                 :            :                "     --to-pattern=GLOB     Show only destinations in the graph\n"
    2251                 :            :                "     --fuzz=SECONDS        Also print services which finished SECONDS earlier\n"
    2252                 :            :                "                           than the latest in the branch\n"
    2253                 :            :                "     --man[=BOOL]          Do [not] check for existence of man pages\n"
    2254                 :            :                "     --generators[=BOOL]   Do [not] run unit generators (requires privileges)\n"
    2255                 :            :                "     --iterations=N        Show the specified number of iterations\n"
    2256                 :            :                "\nCommands:\n"
    2257                 :            :                "  time                     Print time spent in the kernel\n"
    2258                 :            :                "  blame                    Print list of running units ordered by time to init\n"
    2259                 :            :                "  critical-chain [UNIT...] Print a tree of the time critical chain of units\n"
    2260                 :            :                "  plot                     Output SVG graphic showing service initialization\n"
    2261                 :            :                "  dot [UNIT...]            Output dependency graph in %s format\n"
    2262                 :            :                "  log-level [LEVEL]        Get/set logging threshold for manager\n"
    2263                 :            :                "  log-target [TARGET]      Get/set logging target for manager\n"
    2264                 :            :                "  dump                     Output state serialization of service manager\n"
    2265                 :            :                "  cat-config               Show configuration file and drop-ins\n"
    2266                 :            :                "  unit-files               List files and symlinks for units\n"
    2267                 :            :                "  unit-paths               List load directories for units\n"
    2268                 :            :                "  exit-status [STATUS...]  List exit status definitions\n"
    2269                 :            :                "  syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
    2270                 :            :                "  condition CONDITION...   Evaluate conditions and asserts\n"
    2271                 :            :                "  verify FILE...           Check unit files for correctness\n"
    2272                 :            :                "  service-watchdogs [BOOL] Get/set service watchdog state\n"
    2273                 :            :                "  calendar SPEC...         Validate repetitive calendar time events\n"
    2274                 :            :                "  timestamp TIMESTAMP...   Validate a timestamp\n"
    2275                 :            :                "  timespan SPAN...         Validate a time span\n"
    2276                 :            :                "  security [UNIT...]       Analyze security of unit\n"
    2277                 :            :                "\nSee the %s for details.\n"
    2278                 :            :                , program_invocation_short_name
    2279                 :            :                , dot_link
    2280                 :            :                , link
    2281                 :            :         );
    2282                 :            : 
    2283                 :            :         /* When updating this list, including descriptions, apply changes to
    2284                 :            :          * shell-completion/bash/systemd-analyze and shell-completion/zsh/_systemd-analyze too. */
    2285                 :            : 
    2286                 :         12 :         return 0;
    2287                 :            : }
    2288                 :            : 
    2289                 :         16 : static int parse_argv(int argc, char *argv[]) {
    2290                 :            :         enum {
    2291                 :            :                 ARG_VERSION = 0x100,
    2292                 :            :                 ARG_ORDER,
    2293                 :            :                 ARG_REQUIRE,
    2294                 :            :                 ARG_ROOT,
    2295                 :            :                 ARG_SYSTEM,
    2296                 :            :                 ARG_USER,
    2297                 :            :                 ARG_GLOBAL,
    2298                 :            :                 ARG_DOT_FROM_PATTERN,
    2299                 :            :                 ARG_DOT_TO_PATTERN,
    2300                 :            :                 ARG_FUZZ,
    2301                 :            :                 ARG_NO_PAGER,
    2302                 :            :                 ARG_MAN,
    2303                 :            :                 ARG_GENERATORS,
    2304                 :            :                 ARG_ITERATIONS,
    2305                 :            :         };
    2306                 :            : 
    2307                 :            :         static const struct option options[] = {
    2308                 :            :                 { "help",         no_argument,       NULL, 'h'                  },
    2309                 :            :                 { "version",      no_argument,       NULL, ARG_VERSION          },
    2310                 :            :                 { "order",        no_argument,       NULL, ARG_ORDER            },
    2311                 :            :                 { "require",      no_argument,       NULL, ARG_REQUIRE          },
    2312                 :            :                 { "root",         required_argument, NULL, ARG_ROOT             },
    2313                 :            :                 { "system",       no_argument,       NULL, ARG_SYSTEM           },
    2314                 :            :                 { "user",         no_argument,       NULL, ARG_USER             },
    2315                 :            :                 { "global",       no_argument,       NULL, ARG_GLOBAL           },
    2316                 :            :                 { "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN },
    2317                 :            :                 { "to-pattern",   required_argument, NULL, ARG_DOT_TO_PATTERN   },
    2318                 :            :                 { "fuzz",         required_argument, NULL, ARG_FUZZ             },
    2319                 :            :                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER         },
    2320                 :            :                 { "man",          optional_argument, NULL, ARG_MAN              },
    2321                 :            :                 { "generators",   optional_argument, NULL, ARG_GENERATORS       },
    2322                 :            :                 { "host",         required_argument, NULL, 'H'                  },
    2323                 :            :                 { "machine",      required_argument, NULL, 'M'                  },
    2324                 :            :                 { "iterations",   required_argument, NULL, ARG_ITERATIONS       },
    2325                 :            :                 {}
    2326                 :            :         };
    2327                 :            : 
    2328                 :            :         int r, c;
    2329                 :            : 
    2330         [ -  + ]:         16 :         assert(argc >= 0);
    2331         [ -  + ]:         16 :         assert(argv);
    2332                 :            : 
    2333         [ +  - ]:         16 :         while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
    2334   [ +  -  -  -  :         16 :                 switch (c) {
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  +  
                      - ]
    2335                 :            : 
    2336                 :         12 :                 case 'h':
    2337                 :         12 :                         return help(0, NULL, NULL);
    2338                 :            : 
    2339                 :          0 :                 case ARG_VERSION:
    2340                 :          0 :                         return version();
    2341                 :            : 
    2342                 :          0 :                 case ARG_ROOT:
    2343                 :          0 :                         arg_root = optarg;
    2344                 :          0 :                         break;
    2345                 :            : 
    2346                 :          0 :                 case ARG_SYSTEM:
    2347                 :          0 :                         arg_scope = UNIT_FILE_SYSTEM;
    2348                 :          0 :                         break;
    2349                 :            : 
    2350                 :          0 :                 case ARG_USER:
    2351                 :          0 :                         arg_scope = UNIT_FILE_USER;
    2352                 :          0 :                         break;
    2353                 :            : 
    2354                 :          0 :                 case ARG_GLOBAL:
    2355                 :          0 :                         arg_scope = UNIT_FILE_GLOBAL;
    2356                 :          0 :                         break;
    2357                 :            : 
    2358                 :          0 :                 case ARG_ORDER:
    2359                 :          0 :                         arg_dot = DEP_ORDER;
    2360                 :          0 :                         break;
    2361                 :            : 
    2362                 :          0 :                 case ARG_REQUIRE:
    2363                 :          0 :                         arg_dot = DEP_REQUIRE;
    2364                 :          0 :                         break;
    2365                 :            : 
    2366                 :          0 :                 case ARG_DOT_FROM_PATTERN:
    2367         [ #  # ]:          0 :                         if (strv_extend(&arg_dot_from_patterns, optarg) < 0)
    2368                 :          0 :                                 return log_oom();
    2369                 :            : 
    2370                 :          0 :                         break;
    2371                 :            : 
    2372                 :          0 :                 case ARG_DOT_TO_PATTERN:
    2373         [ #  # ]:          0 :                         if (strv_extend(&arg_dot_to_patterns, optarg) < 0)
    2374                 :          0 :                                 return log_oom();
    2375                 :            : 
    2376                 :          0 :                         break;
    2377                 :            : 
    2378                 :          0 :                 case ARG_FUZZ:
    2379                 :          0 :                         r = parse_sec(optarg, &arg_fuzz);
    2380         [ #  # ]:          0 :                         if (r < 0)
    2381                 :          0 :                                 return r;
    2382                 :          0 :                         break;
    2383                 :            : 
    2384                 :          0 :                 case ARG_NO_PAGER:
    2385                 :          0 :                         arg_pager_flags |= PAGER_DISABLE;
    2386                 :          0 :                         break;
    2387                 :            : 
    2388                 :          0 :                 case 'H':
    2389                 :          0 :                         arg_transport = BUS_TRANSPORT_REMOTE;
    2390                 :          0 :                         arg_host = optarg;
    2391                 :          0 :                         break;
    2392                 :            : 
    2393                 :          0 :                 case 'M':
    2394                 :          0 :                         arg_transport = BUS_TRANSPORT_MACHINE;
    2395                 :          0 :                         arg_host = optarg;
    2396                 :          0 :                         break;
    2397                 :            : 
    2398                 :          0 :                 case ARG_MAN:
    2399         [ #  # ]:          0 :                         if (optarg) {
    2400                 :          0 :                                 r = parse_boolean(optarg);
    2401         [ #  # ]:          0 :                                 if (r < 0)
    2402         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    2403                 :            :                                                                "Failed to parse --man= argument.");
    2404                 :            : 
    2405                 :          0 :                                 arg_man = r;
    2406                 :            :                         } else
    2407                 :          0 :                                 arg_man = true;
    2408                 :            : 
    2409                 :          0 :                         break;
    2410                 :            : 
    2411                 :          0 :                 case ARG_GENERATORS:
    2412         [ #  # ]:          0 :                         if (optarg) {
    2413                 :          0 :                                 r = parse_boolean(optarg);
    2414         [ #  # ]:          0 :                                 if (r < 0)
    2415         [ #  # ]:          0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    2416                 :            :                                                                "Failed to parse --generators= argument.");
    2417                 :            : 
    2418                 :          0 :                                 arg_generators = r;
    2419                 :            :                         } else
    2420                 :          0 :                                 arg_generators = true;
    2421                 :            : 
    2422                 :          0 :                         break;
    2423                 :            : 
    2424                 :          0 :                 case ARG_ITERATIONS:
    2425                 :          0 :                         r = safe_atou(optarg, &arg_iterations);
    2426         [ #  # ]:          0 :                         if (r < 0)
    2427         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to parse iterations: %s", optarg);
    2428                 :            : 
    2429                 :          0 :                         break;
    2430                 :            : 
    2431                 :          4 :                 case '?':
    2432                 :          4 :                         return -EINVAL;
    2433                 :            : 
    2434                 :          0 :                 default:
    2435                 :          0 :                         assert_not_reached("Unhandled option code.");
    2436                 :            :                 }
    2437                 :            : 
    2438         [ #  # ]:          0 :         if (arg_scope == UNIT_FILE_GLOBAL &&
    2439   [ #  #  #  # ]:          0 :             !STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify"))
    2440         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    2441                 :            :                                        "Option --global only makes sense with verbs dot, unit-paths, verify.");
    2442                 :            : 
    2443   [ #  #  #  # ]:          0 :         if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER)
    2444         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    2445                 :            :                                        "Option --user is not supported for cat-config right now.");
    2446                 :            : 
    2447   [ #  #  #  # ]:          0 :         if (arg_root && !streq_ptr(argv[optind], "cat-config"))
    2448         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    2449                 :            :                                        "Option --root is only supported for cat-config right now.");
    2450                 :            : 
    2451                 :          0 :         return 1; /* work to do */
    2452                 :            : }
    2453                 :            : 
    2454                 :         16 : static int run(int argc, char *argv[]) {
    2455                 :            : 
    2456                 :            :         static const Verb verbs[] = {
    2457                 :            :                 { "help",              VERB_ANY, VERB_ANY, 0,            help                   },
    2458                 :            :                 { "time",              VERB_ANY, 1,        VERB_DEFAULT, analyze_time           },
    2459                 :            :                 { "blame",             VERB_ANY, 1,        0,            analyze_blame          },
    2460                 :            :                 { "critical-chain",    VERB_ANY, VERB_ANY, 0,            analyze_critical_chain },
    2461                 :            :                 { "plot",              VERB_ANY, 1,        0,            analyze_plot           },
    2462                 :            :                 { "dot",               VERB_ANY, VERB_ANY, 0,            dot                    },
    2463                 :            :                 { "log-level",         VERB_ANY, 2,        0,            get_or_set_log_level   },
    2464                 :            :                 { "log-target",        VERB_ANY, 2,        0,            get_or_set_log_target  },
    2465                 :            :                 /* The following four verbs are deprecated aliases */
    2466                 :            :                 { "set-log-level",     2,        2,        0,            set_log_level          },
    2467                 :            :                 { "get-log-level",     VERB_ANY, 1,        0,            get_log_level          },
    2468                 :            :                 { "set-log-target",    2,        2,        0,            set_log_target         },
    2469                 :            :                 { "get-log-target",    VERB_ANY, 1,        0,            get_log_target         },
    2470                 :            : 
    2471                 :            :                 { "dump",              VERB_ANY, 1,        0,            dump                   },
    2472                 :            :                 { "cat-config",        2,        VERB_ANY, 0,            cat_config             },
    2473                 :            :                 { "unit-files",        VERB_ANY, VERB_ANY, 0,            do_unit_files          },
    2474                 :            :                 { "unit-paths",        1,        1,        0,            dump_unit_paths        },
    2475                 :            :                 { "exit-status",       VERB_ANY, VERB_ANY, 0,            dump_exit_status       },
    2476                 :            :                 { "syscall-filter",    VERB_ANY, VERB_ANY, 0,            dump_syscall_filters   },
    2477                 :            :                 { "condition",         2,        VERB_ANY, 0,            do_condition           },
    2478                 :            :                 { "verify",            2,        VERB_ANY, 0,            do_verify              },
    2479                 :            :                 { "calendar",          2,        VERB_ANY, 0,            test_calendar          },
    2480                 :            :                 { "timestamp",         2,        VERB_ANY, 0,            test_timestamp         },
    2481                 :            :                 { "timespan",          2,        VERB_ANY, 0,            dump_timespan          },
    2482                 :            :                 { "service-watchdogs", VERB_ANY, 2,        0,            service_watchdogs      },
    2483                 :            :                 { "security",          VERB_ANY, VERB_ANY, 0,            do_security            },
    2484                 :            :                 {}
    2485                 :            :         };
    2486                 :            : 
    2487                 :            :         int r;
    2488                 :            : 
    2489                 :         16 :         setlocale(LC_ALL, "");
    2490                 :         16 :         setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */
    2491                 :            : 
    2492                 :         16 :         log_show_color(true);
    2493                 :         16 :         log_parse_environment();
    2494                 :         16 :         log_open();
    2495                 :            : 
    2496                 :         16 :         r = parse_argv(argc, argv);
    2497         [ +  - ]:         16 :         if (r <= 0)
    2498                 :         16 :                 return r;
    2499                 :            : 
    2500                 :          0 :         return dispatch_verb(argc, argv, verbs, NULL);
    2501                 :            : }
    2502                 :            : 
    2503                 :         16 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14