#include <getopt.h>
#include <inttypes.h>
-#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static bool arg_generators = false;
static const char *arg_root = NULL;
static unsigned arg_iterations = 1;
+static usec_t arg_base_time = USEC_INFINITY;
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
return (argc == 1) ? get_log_target(argc, argv, userdata) : set_log_target(argc, argv, userdata);
}
+static bool strv_fnmatch_strv_or_empty(char* const* patterns, char **strv, int flags) {
+ char **s;
+ STRV_FOREACH(s, strv)
+ if (strv_fnmatch_or_empty(patterns, *s, flags))
+ return true;
+
+ return false;
+}
+
+static int do_unit_files(int argc, char *argv[], void *userdata) {
+ _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_hashmap_free_ Hashmap *unit_ids = NULL;
+ _cleanup_hashmap_free_ Hashmap *unit_names = NULL;
+ char **patterns = strv_skip(argv, 1);
+ Iterator i;
+ const char *k, *dst;
+ char **v;
+ int r;
+
+ r = lookup_paths_init(&lp, arg_scope, 0, NULL);
+ if (r < 0)
+ return log_error_errno(r, "lookup_paths_init() failed: %m");
+
+ r = unit_file_build_name_map(&lp, NULL, &unit_ids, &unit_names, NULL);
+ if (r < 0)
+ return log_error_errno(r, "unit_file_build_name_map() failed: %m");
+
+ HASHMAP_FOREACH_KEY(dst, k, unit_ids, i) {
+ if (!strv_fnmatch_or_empty(patterns, k, FNM_NOESCAPE) &&
+ !strv_fnmatch_or_empty(patterns, dst, FNM_NOESCAPE))
+ continue;
+
+ printf("ids: %s → %s\n", k, dst);
+ }
+
+ HASHMAP_FOREACH_KEY(v, k, unit_names, i) {
+ if (!strv_fnmatch_or_empty(patterns, k, FNM_NOESCAPE) &&
+ !strv_fnmatch_strv_or_empty(patterns, v, FNM_NOESCAPE))
+ continue;
+
+ _cleanup_free_ char *j = strv_join(v, ", ");
+ printf("aliases: %s ← %s\n", k, j);
+ }
+
+ return 0;
+}
+
static int dump_unit_paths(int argc, char *argv[], void *userdata) {
_cleanup_(lookup_paths_free) LookupPaths paths = {};
int r;
return 0;
}
+static int dump_exit_status(int argc, char *argv[], void *userdata) {
+ _cleanup_(table_unrefp) Table *table = NULL;
+ int r;
+
+ table = table_new("name", "status", "class");
+ if (!table)
+ return log_oom();
+
+ r = table_set_align_percent(table, table_get_cell(table, 0, 1), 100);
+ if (r < 0)
+ return log_error_errno(r, "Failed to right-align status: %m");
+
+ if (strv_isempty(strv_skip(argv, 1)))
+ for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++) {
+ if (!exit_status_mappings[i].name)
+ continue;
+
+ r = table_add_many(table,
+ TABLE_STRING, exit_status_mappings[i].name,
+ TABLE_INT, (int) i,
+ TABLE_STRING, exit_status_class(i));
+ if (r < 0)
+ return r;
+ }
+ else
+ for (int i = 1; i < argc; i++) {
+ int status;
+
+ status = exit_status_from_string(argv[i]);
+ if (status < 0)
+ return log_error_errno(r, "Invalid exit status \"%s\": %m", argv[i]);
+
+ assert(status >= 0 && (size_t) status < ELEMENTSOF(exit_status_mappings));
+ r = table_add_many(table,
+ TABLE_STRING, exit_status_mappings[status].name ?: "-",
+ TABLE_INT, status,
+ TABLE_STRING, exit_status_class(status) ?: "-");
+ if (r < 0)
+ return r;
+ }
+
+ (void) pager_open(arg_pager_flags);
+
+ return table_print(table, NULL);
+}
+
#if HAVE_SECCOMP
static int load_kernel_syscalls(Set **ret) {
if (syscall[0] == '@')
continue;
- (void) set_remove(s, syscall);
+ free(set_remove(s, syscall));
}
}
printf(" %s%s%s\n", syscall[0] == '@' ? ansi_underline() : "", syscall, ansi_normal());
}
-static int dump_exit_codes(int argc, char *argv[], void *userdata) {
- _cleanup_(table_unrefp) Table *table = NULL;
- int r;
-
- table = table_new("name", "code", "class");
- if (!table)
- return log_oom();
-
- if (strv_isempty(strv_skip(argv, 1)))
- for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++) {
- if (!exit_status_mappings[i].name)
- continue;
-
- r = table_add_many(table,
- TABLE_STRING, exit_status_mappings[i].name,
- TABLE_UINT, i,
- TABLE_STRING, exit_status_class(i));
- if (r < 0)
- return r;
- }
- else
- for (int i = 1; i < argc; i++) {
- int code;
-
- code = exit_status_from_string(argv[i]);
- if (code < 0)
- return log_error_errno(r, "Invalid exit code \"%s\": %m", argv[i]);
-
- assert(code >= 0 && (size_t) code < ELEMENTSOF(exit_status_mappings));
- r = table_add_many(table,
- TABLE_STRING, exit_status_mappings[code].name ?: "-",
- TABLE_UINT, code,
- TABLE_STRING, exit_status_class(code) ?: "-");
- if (r < 0)
- return r;
- }
-
- (void) pager_open(arg_pager_flags);
-
- return table_print(table, NULL);
-}
-
static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
bool first = true;
fflush(stdout);
log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m");
} else if (!set_isempty(kernel)) {
- const char *syscall;
- Iterator j;
+ _cleanup_free_ char **l = NULL;
+ char **syscall;
printf("\n"
"# %sUnlisted System Calls%s (supported by the local kernel, but not included in any of the groups listed above):\n",
ansi_highlight(), ansi_normal());
- SET_FOREACH(syscall, kernel, j)
- printf("# %s\n", syscall);
+ l = set_get_strv(kernel);
+ if (!l)
+ return log_oom();
+
+ strv_sort(l);
+
+ STRV_FOREACH(syscall, l)
+ printf("# %s\n", *syscall);
}
} else {
char **name;
char **p;
usec_t n;
- n = now(CLOCK_REALTIME); /* We want to use the same "base" for all expressions */
+ if (arg_base_time != USEC_INFINITY)
+ n = arg_base_time;
+ else
+ n = now(CLOCK_REALTIME); /* We want to use the same "base" for all expressions */
STRV_FOREACH(p, strv_skip(argv, 1)) {
r = test_calendar_one(n, *p);
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
- /* get ServiceWatchdogs */
if (argc == 1) {
+ /* get ServiceWatchdogs */
r = sd_bus_get_property_trivial(
bus,
"org.freedesktop.systemd1",
printf("%s\n", yes_no(!!b));
- return 0;
- }
+ } else {
+ /* set ServiceWatchdogs */
+ b = parse_boolean(argv[1]);
+ if (b < 0)
+ return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
- /* 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));
}
- 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;
}
if (r < 0)
return log_oom();
- printf("%s [OPTIONS...] {COMMAND} ...\n\n"
- "Profile systemd, show unit dependencies, check unit files.\n\n"
+ printf("%s [OPTIONS...] COMMAND ...\n\n"
+ "%sProfile systemd, show unit dependencies, check unit files.%s\n"
+ "\nCommands:\n"
+ " [time] Print time required to boot the machine\n"
+ " blame Print list of running units ordered by time to init\n"
+ " critical-chain [UNIT...] Print a tree of the time critical chain of units\n"
+ " plot Output SVG graphic showing service initialization\n"
+ " dot [UNIT...] Output dependency graph in %s format\n"
+ " dump Output state serialization of service manager\n"
+ " cat-config Show configuration file and drop-ins\n"
+ " unit-files List files and symlinks for units\n"
+ " unit-paths List load directories for units\n"
+ " exit-status [STATUS...] List exit status definitions\n"
+ " syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
+ " condition CONDITION... Evaluate conditions and asserts\n"
+ " verify FILE... Check unit files for correctness\n"
+ " calendar SPEC... Validate repetitive calendar time events\n"
+ " timestamp TIMESTAMP... Validate a timestamp\n"
+ " timespan SPAN... Validate a time span\n"
+ " security [UNIT...] Analyze security of unit\n"
+ "\nOptions:\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --man[=BOOL] Do [not] check for existence of man pages\n"
" --generators[=BOOL] Do [not] run unit generators (requires privileges)\n"
" --iterations=N Show the specified number of iterations\n"
- "\nCommands:\n"
- " time Print time spent in the kernel\n"
- " blame Print list of running units ordered by time to init\n"
- " critical-chain [UNIT...] Print a tree of the time critical chain of units\n"
- " plot Output SVG graphic showing service initialization\n"
- " dot [UNIT...] Output dependency graph in %s 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"
- " cat-config Show configuration file and drop-ins\n"
- " unit-paths List load directories for units\n"
- " exit-codes List exit code definitions\n"
- " syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
- " condition CONDITION... Evaluate conditions and asserts\n"
- " verify FILE... Check unit files for correctness\n"
- " service-watchdogs [BOOL] Get/set service watchdog state\n"
- " calendar SPEC... Validate repetitive calendar time events\n"
- " timestamp TIMESTAMP... Validate a timestamp\n"
- " timespan SPAN... Validate a time span\n"
- " security [UNIT...] Analyze security of unit\n"
+ " --base-time=TIMESTAMP Calculate calendar times relative to specified time\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
+ , ansi_highlight()
+ , ansi_normal()
, dot_link
, link
);
ARG_MAN,
ARG_GENERATORS,
ARG_ITERATIONS,
+ ARG_BASE_TIME,
};
static const struct option options[] = {
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "iterations", required_argument, NULL, ARG_ITERATIONS },
+ { "base-time", required_argument, NULL, ARG_BASE_TIME },
{}
};
break;
+ case ARG_BASE_TIME:
+ r = parse_timestamp(optarg, &arg_base_time);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --base-time= parameter: %s", optarg);
+
+ break;
+
case '?':
return -EINVAL;
{ "critical-chain", VERB_ANY, VERB_ANY, 0, analyze_critical_chain },
{ "plot", VERB_ANY, 1, 0, analyze_plot },
{ "dot", VERB_ANY, VERB_ANY, 0, dot },
+ /* The following seven verbs are deprecated */
{ "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 },
+ { "service-watchdogs", VERB_ANY, 2, 0, service_watchdogs },
{ "dump", VERB_ANY, 1, 0, dump },
{ "cat-config", 2, VERB_ANY, 0, cat_config },
+ { "unit-files", VERB_ANY, VERB_ANY, 0, do_unit_files },
{ "unit-paths", 1, 1, 0, dump_unit_paths },
- { "exit-codes", VERB_ANY, VERB_ANY, 0, dump_exit_codes },
+ { "exit-status", VERB_ANY, VERB_ANY, 0, dump_exit_status },
{ "syscall-filter", VERB_ANY, VERB_ANY, 0, dump_syscall_filters },
{ "condition", 2, VERB_ANY, 0, do_condition },
{ "verify", 2, VERB_ANY, 0, do_verify },
{ "calendar", 2, VERB_ANY, 0, test_calendar },
{ "timestamp", 2, VERB_ANY, 0, test_timestamp },
{ "timespan", 2, VERB_ANY, 0, dump_timespan },
- { "service-watchdogs", VERB_ANY, 2, 0, service_watchdogs },
{ "security", VERB_ANY, VERB_ANY, 0, do_security },
{}
};