X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fanalyze%2Fanalyze.c;h=46a97eb8e7f9682e4c518d425d27c6a8ef5a9f1f;hb=8744505aaefad761cba0f0e5afaaf6bcec53906e;hp=4c5fcfe8c2eb6510c4ec3aa06e416579123c8d3d;hpb=7e690cefd4f09bb6370f91611f623adea841bdf4;p=elogind.git diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 4c5fcfe8c..46a97eb8e 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -41,6 +41,7 @@ #include "special.h" #include "hashmap.h" #include "pager.h" +#include "analyze-verify.h" #define SCALE_X (0.1 / 1000.0) /* pixels per us */ #define SCALE_Y (20.0) @@ -74,6 +75,7 @@ static bool arg_no_pager = false; static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; static char *arg_host = NULL; static bool arg_user = false; +static bool arg_man = true; struct boot_times { usec_t firmware_time; @@ -275,7 +277,8 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) { return c; fail: - free_unit_times(unit_times, (unsigned) c); + if (unit_times) + free_unit_times(unit_times, (unsigned) c); return r; } @@ -845,7 +848,8 @@ static int list_dependencies(sd_bus *bus, const char *name) { char ts[FORMAT_TIMESPAN_MAX]; struct unit_times *times; int r; - const char *path, *id; + const char *id; + _cleanup_free_ char *path = NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; struct boot_times *boot; @@ -903,7 +907,7 @@ static int analyze_critical_chain(sd_bus *bus, char *names[]) { if (n <= 0) return n; - h = hashmap_new(string_hash_func, string_compare_func); + h = hashmap_new(&string_hash_ops); if (!h) return -ENOMEM; @@ -1178,43 +1182,40 @@ static int set_log_level(sd_bus *bus, char **args) { return 0; } -static int help(void) { +static void help(void) { pager_open_if_enabled(); printf("%s [OPTIONS...] {COMMAND} ...\n\n" - "Process systemd profiling information.\n\n" + "Profile systemd, show unit dependencies, check unit files.\n\n" " -h --help Show this help\n" " --version Show package version\n" " --no-pager Do not pipe output into a pager\n" - " --system Connect to system manager\n" - " --user Connect to user manager\n" + " --system Operate on system systemd instance\n" + " --user Operate on user systemd instance\n" " -H --host=[USER@]HOST Operate on remote host\n" " -M --machine=CONTAINER Operate on local container\n" - " --order When generating a dependency graph, show only order\n" - " --require When generating a dependency graph, show only requirement\n" - " --from-pattern=GLOB, --to-pattern=GLOB\n" - " When generating a dependency graph, filter only origins\n" - " or destinations, respectively\n" - " --fuzz=TIMESPAN When printing the tree of the critical chain, print also\n" - " services, which finished TIMESPAN earlier, than the\n" - " latest in the branch. The unit of TIMESPAN is seconds\n" - " unless specified with a different unit, i.e. 50ms\n\n" + " --order Show only order in the graph\n" + " --require Show only requirement in the graph\n" + " --from-pattern=GLOB Show only origins in the graph\n" + " --to-pattern=GLOB Show only destinations in the graph\n" + " --fuzz=SECONDS Also print also services which finished SECONDS\n" + " earlier than the latest in the branch\n" + " --man[=BOOL] Do [not] check for existence of man pages\n\n" "Commands:\n" - " time Print time spent in the kernel before reaching userspace\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" " plot Output SVG graphic showing service initialization\n" " dot Output dependency graph in dot(1) format\n" " set-log-level LEVEL Set logging threshold for systemd\n" - " dump Output state serialization of service manager\n", - program_invocation_short_name); + " dump Output state serialization of service manager\n" + " verify FILE... Check unit files for correctness\n" + , program_invocation_short_name); /* When updating this list, including descriptions, apply - * changes to shell-completion/bash/systemd and - * shell-completion/systemd-zsh-completion.zsh too. */ - - return 0; + * changes to shell-completion/bash/systemd-analyze and + * shell-completion/zsh/_systemd-analyze too. */ } static int parse_argv(int argc, char *argv[]) { @@ -1227,7 +1228,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_DOT_FROM_PATTERN, ARG_DOT_TO_PATTERN, ARG_FUZZ, - ARG_NO_PAGER + ARG_NO_PAGER, + ARG_MAN, }; static const struct option options[] = { @@ -1241,6 +1243,7 @@ static int parse_argv(int argc, char *argv[]) { { "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN }, { "fuzz", required_argument, NULL, ARG_FUZZ }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "man", optional_argument, NULL, ARG_MAN }, { "host", required_argument, NULL, 'H' }, { "machine", required_argument, NULL, 'M' }, {} @@ -1251,12 +1254,12 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) { - + while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) switch (c) { case 'h': - return help(); + help(); + return 0; case ARG_VERSION: puts(PACKAGE_STRING); @@ -1307,23 +1310,35 @@ static int parse_argv(int argc, char *argv[]) { break; case 'M': - arg_transport = BUS_TRANSPORT_CONTAINER; + arg_transport = BUS_TRANSPORT_MACHINE; arg_host = optarg; break; + case ARG_MAN: + if (optarg) { + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --man= argument."); + return -EINVAL; + } + + arg_man = !!r; + } else + arg_man = true; + + break; + case '?': return -EINVAL; default: - assert_not_reached("Unhandled option"); + assert_not_reached("Unhandled option code."); } - } - return 1; + return 1; /* work to do */ } int main(int argc, char *argv[]) { - _cleanup_bus_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -1335,28 +1350,36 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - r = bus_open_transport(arg_transport, arg_host, arg_user, &bus); - if (r < 0) { - log_error("Failed to create bus connection: %s", strerror(-r)); - goto finish; - } + if (streq_ptr(argv[optind], "verify")) + r = verify_units(argv+optind+1, + arg_user ? SYSTEMD_USER : SYSTEMD_SYSTEM, + arg_man); + else { + _cleanup_bus_close_unref_ sd_bus *bus = NULL; + + r = bus_open_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 - log_error("Unknown operation '%s'.", argv[optind]); + 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 + log_error("Unknown operation '%s'.", argv[optind]); + } finish: pager_close();