#include "terminal-util.h"
#include "unit-name.h"
#include "util.h"
+#include "verbs.h"
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
static usec_t arg_fuzz = 0;
static bool arg_no_pager = false;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
-static bool arg_user = false;
+static const char *arg_host = NULL;
+static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
static bool arg_man = true;
static bool arg_generators = false;
char *architecture;
};
+static int acquire_bus(bool need_full_bus, sd_bus **bus) {
+ bool user = arg_scope != UNIT_FILE_SYSTEM;
+
+ if (need_full_bus)
+ return bus_connect_transport(arg_transport, arg_host, user, bus);
+ else
+ return bus_connect_transport_systemd(arg_transport, arg_host, user, bus);
+}
+
static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
return -EINPROGRESS;
}
- if (arg_user) {
+ if (arg_scope == UNIT_FILE_SYSTEM) {
+ if (times.initrd_time > 0)
+ times.kernel_done_time = times.initrd_time;
+ else
+ times.kernel_done_time = times.userspace_time;
+ } else {
/*
* User-instance-specific timestamps processing
* (see comment to reverse_offset in struct boot_times).
subtract_timestamp(×.unitsload_start_time, times.reverse_offset);
subtract_timestamp(×.unitsload_finish_time, times.reverse_offset);
- } else {
- if (times.initrd_time)
- times.kernel_done_time = times.initrd_time;
- else
- times.kernel_done_time = times.userspace_time;
}
cached = true;
continue;
t->name = strdup(u.id);
- if (t->name == NULL) {
+ if (!t->name) {
r = log_oom();
goto fail;
}
return c;
fail:
- if (unit_times)
- free_unit_times(unit_times, (unsigned) c);
+ free_unit_times(unit_times, (unsigned) c);
return r;
}
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
hostname_map,
+ BUS_MAP_STRDUP,
&error,
+ NULL,
host);
if (r < 0)
log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r));
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
manager_map,
+ BUS_MAP_STRDUP,
&error,
+ NULL,
host);
if (r < 0)
return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r));
"ActiveEnterTimestampMonotonic",
&activated_time);
if (r < 0) {
- log_info_errno(r, "default.target seems not to be started. Continuing...");
+ log_info_errno(r, "Could not get time to reach default.target. Continuing...");
activated_time = USEC_INFINITY;
}
size = sizeof(buf);
size = strpcpyf(&ptr, size, "Startup finished in ");
- if (t->firmware_time)
+ if (t->firmware_time > 0)
size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
- if (t->loader_time)
+ if (t->loader_time > 0)
size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
- if (t->kernel_time)
+ if (t->kernel_time > 0)
size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
if (t->initrd_time > 0)
size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
- strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
+ if (t->kernel_time > 0)
+ strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
- if (unit_id && activated_time != USEC_INFINITY)
+ if (unit_id && activated_time > 0 && activated_time != USEC_INFINITY)
size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id, format_timespan(ts, sizeof(ts), activated_time - t->userspace_time, USEC_PER_MSEC));
+ else if (unit_id && activated_time == 0)
+ size = strpcpyf(&ptr, size, "\n%s was never reached", unit_id);
+ else if (unit_id && activated_time == USEC_INFINITY)
+ size = strpcpyf(&ptr, size, "\nCould not get time to reach %s.",unit_id);
+ else if (!unit_id)
+ size = strpcpyf(&ptr, size, "\ncould not find default.target");
+
ptr = strdup(buf);
if (!ptr)
}
}
-static int analyze_plot(sd_bus *bus) {
+static int analyze_plot(int argc, char *argv[], void *userdata) {
_cleanup_(free_host_infop) struct host_info *host = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
struct unit_times *times;
struct boot_times *boot;
- int n, m = 1, y=0;
+ int n, m = 1, y = 0, r;
double width;
_cleanup_free_ char *pretty_times = NULL;
struct unit_times *u;
+ r = acquire_bus(true, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
n = acquire_boot_times(bus, &boot);
if (n < 0)
return n;
if (boot->firmware_time > boot->loader_time)
m++;
- if (boot->loader_time) {
+ if (boot->loader_time > 0) {
m++;
if (width < 1000.0)
width = 1000.0;
}
- if (boot->initrd_time)
+ if (boot->initrd_time > 0)
m++;
- if (boot->kernel_time)
+ if (boot->kernel_time > 0)
m++;
for (u = times; u < times + n; u++) {
svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
- if (boot->firmware_time) {
+ if (boot->firmware_time > 0) {
svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y);
svg_text(true, -(double) boot->firmware_time, y, "firmware");
y++;
}
- if (boot->loader_time) {
+ if (boot->loader_time > 0) {
svg_bar("loader", -(double) boot->loader_time, 0, y);
svg_text(true, -(double) boot->loader_time, y, "loader");
y++;
}
- if (boot->kernel_time) {
+ if (boot->kernel_time > 0) {
svg_bar("kernel", 0, boot->kernel_done_time, y);
svg_text(true, 0, y, "kernel");
y++;
}
- if (boot->initrd_time) {
+ if (boot->initrd_time > 0) {
svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
svg_text(true, boot->initrd_time, y, "initrd");
y++;
printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
if (times) {
- if (times->time)
+ if (times->time > 0)
printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal());
assert(deps);
path = unit_dbus_path_from_name(name);
- if (path == NULL)
+ if (!path)
return -ENOMEM;
return bus_get_unit_property_strv(bus, path, "After", deps);
return usb - usa;
}
+static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) {
+ return times &&
+ times->activated > 0 && times->activated <= boot->finish_time;
+}
+
static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int level, char ***units,
unsigned int branches) {
_cleanup_strv_free_ char **deps = NULL;
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times
- && times->activated
- && times->activated <= boot->finish_time
- && (times->activated >= service_longest
- || service_longest == 0)) {
+ if (times_in_range(times, boot) &&
+ (times->activated >= service_longest
+ || service_longest == 0)) {
service_longest = times->activated;
break;
}
}
- if (service_longest == 0 )
+ if (service_longest == 0)
return r;
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times && times->activated && times->activated <= boot->finish_time && (service_longest - times->activated) <= arg_fuzz)
+ if (times_in_range(times, boot) &&
+ service_longest - times->activated <= arg_fuzz)
to_print++;
}
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (!times
- || !times->activated
- || times->activated > boot->finish_time
- || service_longest - times->activated > arg_fuzz)
+ if (!times_in_range(times, boot) ||
+ service_longest - times->activated > arg_fuzz)
continue;
to_print--;
if (r < 0)
return r;
- if (!to_print)
+ if (to_print == 0)
break;
}
return 0;
assert(bus);
path = unit_dbus_path_from_name(name);
- if (path == NULL)
+ if (!path)
return -ENOMEM;
r = sd_bus_get_property(
return list_dependencies_one(bus, name, 0, &units, 0);
}
-static int analyze_critical_chain(sd_bus *bus, char *names[]) {
+static int analyze_critical_chain(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
struct unit_times *times;
unsigned int i;
Hashmap *h;
int n, r;
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
n = acquire_time_data(bus, ×);
if (n <= 0)
return n;
h = hashmap_new(&string_hash_ops);
if (!h)
- return -ENOMEM;
+ return log_oom();
- for (i = 0; i < (unsigned)n; i++) {
+ for (i = 0; i < (unsigned) n; i++) {
r = hashmap_put(h, times[i].name, ×[i]);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add entry to hashmap: %m");
}
unit_times_hashmap = h;
- pager_open(arg_no_pager, false);
+ (void) pager_open(arg_no_pager, false);
puts("The time after the unit is active or started is printed after the \"@\" character.\n"
"The time the unit takes to start is printed after the \"+\" character.\n");
- if (!strv_isempty(names)) {
+ if (argc > 1) {
char **name;
- STRV_FOREACH(name, names)
+ STRV_FOREACH(name, strv_skip(argv, 1))
list_dependencies(bus, *name);
} else
list_dependencies(bus, SPECIAL_DEFAULT_TARGET);
- hashmap_free(h);
+ h = hashmap_free(h);
free_unit_times(times, (unsigned) n);
return 0;
}
-static int analyze_blame(sd_bus *bus) {
+static int analyze_blame(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
struct unit_times *times;
unsigned i;
- int n;
+ int n, r;
+
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
n = acquire_time_data(bus, ×);
if (n <= 0)
qsort(times, n, sizeof(struct unit_times), compare_unit_time);
- pager_open(arg_no_pager, false);
+ (void) pager_open(arg_no_pager, false);
for (i = 0; i < (unsigned) n; i++) {
char ts[FORMAT_TIMESPAN_MAX];
return 0;
}
-static int analyze_time(sd_bus *bus) {
+static int analyze_time(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *buf = NULL;
int r;
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
r = pretty_boot_time(bus, &buf);
if (r < 0)
return r;
return 0;
}
-static int dot(sd_bus *bus, char* patterns[]) {
+static int dot(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_strv_free_ char **expanded_patterns = NULL;
_cleanup_strv_free_ char **expanded_from_patterns = NULL;
_cleanup_strv_free_ char **expanded_to_patterns = NULL;
int r;
UnitInfo u;
- r = expand_patterns(bus, patterns, &expanded_patterns);
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
+ r = expand_patterns(bus, strv_skip(argv, 1), &expanded_patterns);
if (r < 0)
return r;
return 0;
}
-static int dump(sd_bus *bus, char **args) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+static int dump(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
const char *text = NULL;
int r;
- if (!strv_isempty(args)) {
- log_error("Too many arguments.");
- return -E2BIG;
- }
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
- pager_open(arg_no_pager, false);
+ (void) pager_open(arg_no_pager, false);
r = sd_bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Dump",
- &error,
- &reply,
- "");
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Dump",
+ &error,
+ &reply,
+ NULL);
if (r < 0)
- return log_error_errno(r, "Failed issue method call: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &text);
if (r < 0)
return 0;
}
-static int set_log_level(sd_bus *bus, char **args) {
+static int set_log_level(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
- assert(bus);
- assert(args);
+ assert(argc == 2);
+ assert(argv);
- if (strv_length(args) != 1) {
- log_error("This command expects one argument only.");
- return -E2BIG;
- }
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
r = sd_bus_set_property(
bus,
"LogLevel",
&error,
"s",
- args[0]);
+ argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
return 0;
}
-static int get_log_level(sd_bus *bus, char **args) {
+static int get_log_level(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *level = NULL;
+ int r;
- assert(bus);
- assert(args);
-
- if (!strv_isempty(args)) {
- log_error("Too many arguments.");
- return -E2BIG;
- }
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
r = sd_bus_get_property_string(
bus,
return 0;
}
-static int set_log_target(sd_bus *bus, char **args) {
+static int get_or_set_log_level(int argc, char *argv[], void *userdata) {
+ return (argc == 1) ? get_log_level(argc, argv, userdata) : set_log_level(argc, argv, userdata);
+}
+
+static int set_log_target(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
- assert(bus);
- assert(args);
+ assert(argc == 2);
+ assert(argv);
- if (strv_length(args) != 1) {
- log_error("This command expects one argument only.");
- return -E2BIG;
- }
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
r = sd_bus_set_property(
bus,
"LogTarget",
&error,
"s",
- args[0]);
+ argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
return 0;
}
-static int get_log_target(sd_bus *bus, char **args) {
+static int get_log_target(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *target = NULL;
+ int r;
- assert(bus);
- assert(args);
-
- if (!strv_isempty(args)) {
- log_error("Too many arguments.");
- return -E2BIG;
- }
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
r = sd_bus_get_property_string(
bus,
return 0;
}
+static int get_or_set_log_target(int argc, char *argv[], void *userdata) {
+ return (argc == 1) ? get_log_target(argc, argv, userdata) : set_log_target(argc, argv, userdata);
+}
+
+static int dump_unit_paths(int argc, char *argv[], void *userdata) {
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ int r;
+ char **p;
+
+ r = lookup_paths_init(&paths, arg_scope, 0, NULL);
+ if (r < 0)
+ return log_error_errno(r, "lookup_paths_init() failed: %m");
+
+ STRV_FOREACH(p, paths.search_path)
+ puts(*p);
+
+ return 0;
+}
+
#if HAVE_SECCOMP
static void dump_syscall_filter(const SyscallFilterSet *set) {
const char *syscall;
printf(" %s\n", syscall);
}
-static int dump_syscall_filters(char** names) {
+static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
bool first = true;
- pager_open(arg_no_pager, false);
+ (void) pager_open(arg_no_pager, false);
- if (strv_isempty(names)) {
+ if (strv_isempty(strv_skip(argv, 1))) {
int i;
for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
} else {
char **name;
- STRV_FOREACH(name, names) {
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
const SyscallFilterSet *set;
if (!first)
}
#else
-static int dump_syscall_filters(char** names) {
+static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
log_error("Not compiled with syscall filters, sorry.");
return -EOPNOTSUPP;
}
#endif
-static int test_calendar(char **args) {
+static int test_calendar(int argc, char *argv[], void *userdata) {
int ret = 0, r;
char **p;
usec_t n;
- if (strv_isempty(args)) {
- log_error("Expected at least one calendar specification string as argument.");
- return -EINVAL;
- }
-
n = now(CLOCK_REALTIME);
- STRV_FOREACH(p, args) {
+ STRV_FOREACH(p, strv_skip(argv, 1)) {
_cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
_cleanup_free_ char *t = NULL;
usec_t next;
r = calendar_spec_to_string(spec, &t);
if (r < 0) {
- ret = log_error_errno(r, "Failed to fomat calendar specification '%s': %m", *p);
+ ret = log_error_errno(r, "Failed to format calendar specification '%s': %m", *p);
continue;
}
return ret;
}
-static void help(void) {
+static int service_watchdogs(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ int b, r;
+
+ assert(IN_SET(argc, 1, 2));
+ assert(argv);
+
+ r = acquire_bus(false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
+ /* get ServiceWatchdogs */
+ if (argc == 1) {
+ r = sd_bus_get_property_trivial(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ServiceWatchdogs",
+ &error,
+ 'b',
+ &b);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
+
+ printf("%s\n", yes_no(!!b));
+
+ return 0;
+ }
+
+ /* set ServiceWatchdogs */
+ b = parse_boolean(argv[1]);
+ if (b < 0) {
+ log_error("Failed to parse service-watchdogs argument.");
+ return -EINVAL;
+ }
+
+ r = sd_bus_set_property(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ServiceWatchdogs",
+ &error,
+ "b",
+ b);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
+static int do_verify(int argc, char *argv[], void *userdata) {
+ return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators);
+}
+
+static int help(int argc, char *argv[], void *userdata) {
- pager_open(arg_no_pager, false);
+ (void) pager_open(arg_no_pager, false);
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Profile systemd, show unit dependencies, check unit files.\n\n"
" --no-pager Do not pipe output into a pager\n"
" --system Operate on system systemd instance\n"
" --user Operate on user systemd instance\n"
+ " --global Operate on global user configuration\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" --order Show only order in the graph\n"
"Commands:\n"
" time Print time spent in the kernel\n"
" blame Print list of running units ordered by time to init\n"
- " critical-chain Print a tree of the time critical chain of units\n"
+ " critical-chain [UNIT...] Print a tree of the time critical chain of units\n"
" plot Output SVG graphic showing service initialization\n"
- " dot Output dependency graph in man:dot(1) format\n"
- " set-log-level LEVEL Set logging threshold for manager\n"
- " set-log-target TARGET Set logging target for manager\n"
- " get-log-level Get logging threshold for manager\n"
- " get-log-target Get logging target for manager\n"
+ " dot [UNIT...] Output dependency graph in man:dot(1) format\n"
+ " log-level [LEVEL] Get/set logging threshold for manager\n"
+ " log-target [TARGET] Get/set logging target for manager\n"
" dump Output state serialization of service manager\n"
+ " unit-paths List load directories for units\n"
" syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
" verify FILE... Check unit files for correctness\n"
" calendar SPEC... Validate repetitive calendar time events\n"
+ " service-watchdogs [BOOL] Get/set service watchdog state\n"
, program_invocation_short_name);
/* When updating this list, including descriptions, apply
* changes to shell-completion/bash/systemd-analyze and
* shell-completion/zsh/_systemd-analyze too. */
+
+ return 0;
}
static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_ORDER,
ARG_REQUIRE,
- ARG_USER,
ARG_SYSTEM,
+ ARG_USER,
+ ARG_GLOBAL,
ARG_DOT_FROM_PATTERN,
ARG_DOT_TO_PATTERN,
ARG_FUZZ,
{ "version", no_argument, NULL, ARG_VERSION },
{ "order", no_argument, NULL, ARG_ORDER },
{ "require", no_argument, NULL, ARG_REQUIRE },
- { "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
+ { "user", no_argument, NULL, ARG_USER },
+ { "global", no_argument, NULL, ARG_GLOBAL },
{ "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN },
{ "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN },
{ "fuzz", required_argument, NULL, ARG_FUZZ },
switch (c) {
case 'h':
- help();
- return 0;
+ return help(0, NULL, NULL);
case ARG_VERSION:
return version();
+ case ARG_SYSTEM:
+ arg_scope = UNIT_FILE_SYSTEM;
+ break;
+
case ARG_USER:
- arg_user = true;
+ arg_scope = UNIT_FILE_USER;
break;
- case ARG_SYSTEM:
- arg_user = false;
+ case ARG_GLOBAL:
+ arg_scope = UNIT_FILE_GLOBAL;
break;
case ARG_ORDER:
assert_not_reached("Unhandled option code.");
}
+ if (arg_scope == UNIT_FILE_GLOBAL &&
+ !STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify")) {
+ log_error("Option --global only makes sense with verbs dot, unit-paths, verify.");
+ return -EINVAL;
+ }
+
return 1; /* work to do */
}
int main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "help", VERB_ANY, VERB_ANY, 0, help },
+ { "time", VERB_ANY, 1, VERB_DEFAULT, analyze_time },
+ { "blame", VERB_ANY, 1, 0, analyze_blame },
+ { "critical-chain", VERB_ANY, VERB_ANY, 0, analyze_critical_chain },
+ { "plot", VERB_ANY, 1, 0, analyze_plot },
+ { "dot", VERB_ANY, VERB_ANY, 0, dot },
+ { "log-level", VERB_ANY, 2, 0, get_or_set_log_level },
+ { "log-target", VERB_ANY, 2, 0, get_or_set_log_target },
+ /* The following four verbs are deprecated aliases */
+ { "set-log-level", 2, 2, 0, set_log_level },
+ { "get-log-level", VERB_ANY, 1, 0, get_log_level },
+ { "set-log-target", 2, 2, 0, set_log_target },
+ { "get-log-target", VERB_ANY, 1, 0, get_log_target },
+ { "dump", VERB_ANY, 1, 0, dump },
+ { "unit-paths", 1, 1, 0, dump_unit_paths },
+ { "syscall-filter", VERB_ANY, VERB_ANY, 0, dump_syscall_filters },
+ { "verify", 2, VERB_ANY, 0, do_verify },
+ { "calendar", 2, VERB_ANY, 0, test_calendar },
+ { "service-watchdogs", VERB_ANY, 2, 0, service_watchdogs },
+ {}
+ };
+
int r;
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */
+
log_parse_environment();
log_open();
if (r <= 0)
goto finish;
- if (streq_ptr(argv[optind], "verify"))
- r = verify_units(argv+optind+1,
- arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
- arg_man,
- arg_generators);
- else {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-
- r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
- if (r < 0) {
- log_error_errno(r, "Failed to create bus connection: %m");
- goto finish;
- }
-
- if (!argv[optind] || streq(argv[optind], "time"))
- r = analyze_time(bus);
- else if (streq(argv[optind], "blame"))
- r = analyze_blame(bus);
- else if (streq(argv[optind], "critical-chain"))
- r = analyze_critical_chain(bus, argv+optind+1);
- else if (streq(argv[optind], "plot"))
- r = analyze_plot(bus);
- else if (streq(argv[optind], "dot"))
- r = dot(bus, argv+optind+1);
- else if (streq(argv[optind], "dump"))
- r = dump(bus, argv+optind+1);
- else if (streq(argv[optind], "set-log-level"))
- r = set_log_level(bus, argv+optind+1);
- else if (streq(argv[optind], "get-log-level"))
- r = get_log_level(bus, argv+optind+1);
- else if (streq(argv[optind], "set-log-target"))
- r = set_log_target(bus, argv+optind+1);
- else if (streq(argv[optind], "get-log-target"))
- r = get_log_target(bus, argv+optind+1);
- else if (streq(argv[optind], "syscall-filter"))
- r = dump_syscall_filters(argv+optind+1);
- else if (streq(argv[optind], "calendar"))
- r = test_calendar(argv+optind+1);
- else
- log_error("Unknown operation '%s'.", argv[optind]);
- }
+ r = dispatch_verb(argc, argv, verbs, NULL);
finish:
pager_close();