#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 const char *arg_host = NULL;
static bool arg_user = false;
static bool arg_man = true;
static bool arg_generators = false;
}
}
-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;
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;
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)
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);
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 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 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,
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);
- 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)
}
#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;
return ret;
}
-static void help(void) {
+static int do_verify(int argc, char *argv[], void *userdata) {
+ return verify_units(strv_skip(argv, 1),
+ arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
+ arg_man,
+ arg_generators);
+}
+
+static int help(int argc, char *argv[], void *userdata) {
pager_open(arg_no_pager, false);
"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"
+ " dot [UNIT...] 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"
/* 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[]) {
switch (c) {
case 'h':
- help();
- return 0;
+ return help(0, NULL, NULL);
case ARG_VERSION:
return version();
}
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 },
+ { "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 },
+ { "syscall-filter", VERB_ANY, VERB_ANY, 0, dump_syscall_filters },
+ { "verify", 2, VERB_ANY, 0, do_verify },
+ { "calendar", 2, VERB_ANY, 0, test_calendar },
+ {}
+ };
+
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 = acquire_bus(streq_ptr(argv[optind], "plot"), &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();