#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include "sd-bus.h"
#include "alloc-util.h"
#include "analyze-security.h"
#include "analyze-verify.h"
+#include "build.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "locale-util.h"
#include "log.h"
#include "main-func.h"
+#include "nulstr-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
#if HAVE_SECCOMP
# include "seccomp-util.h"
#endif
+#include "sort-util.h"
#include "special.h"
#include "strv.h"
#include "strxcpyx.h"
-#include "time-util.h"
#include "terminal-util.h"
+#include "time-util.h"
#include "unit-name.h"
#include "util.h"
#include "verbs.h"
-#define SCALE_X (0.1 / 1000.0) /* pixels per us */
+#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
#define svg(...) printf(__VA_ARGS__)
DEP_ORDER,
DEP_REQUIRE
} arg_dot = DEP_ALL;
-static char** arg_dot_from_patterns = NULL;
-static char** arg_dot_to_patterns = NULL;
+static char **arg_dot_from_patterns = NULL;
+static char **arg_dot_to_patterns = NULL;
static usec_t arg_fuzz = 0;
static PagerFlags arg_pager_flags = 0;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static bool arg_man = true;
static bool arg_generators = false;
static const char *arg_root = NULL;
+static unsigned arg_iterations = 1;
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
if (r < 0)
return log_error_errno(r, "Failed to get timestamp properties: %s", bus_error_message(&error, r));
- if (times.finish_time <= 0) {
- log_error("Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
- "Please try again later.\n"
- "Hint: Use 'systemctl%s list-jobs' to see active jobs",
- times.finish_time,
- arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
- return -EINPROGRESS;
- }
+ if (times.finish_time <= 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINPROGRESS),
+ "Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
+ "Please try again later.\n"
+ "Hint: Use 'systemctl%s list-jobs' to see active jobs",
+ times.finish_time,
+ arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) {
/* security_start_time is set when systemd is not running under container environment. */
*/
times.reverse_offset = times.userspace_time;
- times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time = times.userspace_time =
- times.security_start_time = times.security_finish_time = 0;
+ times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time =
+ times.userspace_time = times.security_start_time = times.security_finish_time = 0;
subtract_timestamp(×.finish_time, times.reverse_offset);
}
static void free_host_info(struct host_info *hi) {
-
if (!hi)
return;
free(hi);
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info *, free_host_info);
static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
static const struct bus_properties_map property_map[] = {
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
struct unit_times *t;
- if (!GREEDY_REALLOC(unit_times, allocated, c+2))
+ if (!GREEDY_REALLOC(unit_times, allocated, c + 2))
return log_oom();
- unit_times[c+1].has_data = false;
+ unit_times[c + 1].has_data = false;
t = &unit_times[c];
t->name = NULL;
NULL,
t);
if (r < 0)
- return log_error_errno(r, "Failed to get timestamp properties of unit %s: %s", u.id, bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to get timestamp properties of unit %s: %s",
+ u.id, bus_error_message(&error, r));
subtract_timestamp(&t->activating, boot_times->reverse_offset);
subtract_timestamp(&t->activated, boot_times->reverse_offset);
};
static const struct bus_properties_map manager_map[] = {
- { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
- { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
+ { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
+ { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
{}
};
}
}
- r = bus_map_all_properties(system_bus ?: bus,
- "org.freedesktop.hostname1",
- "/org/freedesktop/hostname1",
- hostname_map,
- BUS_MAP_STRDUP,
- &error,
- NULL,
- host);
+ r = bus_map_all_properties(
+ system_bus ?: bus,
+ "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, ignoring: %s", bus_error_message(&error, r));
+ log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s",
+ bus_error_message(&error, r));
sd_bus_error_free(&error);
}
manager:
- r = bus_map_all_properties(bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- manager_map,
- BUS_MAP_STRDUP,
- &error,
- NULL,
- host);
+ r = bus_map_all_properties(
+ bus,
+ "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));
+ return log_error_errno(r, "Failed to get host information from systemd: %s",
+ bus_error_message(&error, r));
*hi = TAKE_PTR(host);
-
return 0;
}
char *ptr;
int r;
usec_t activated_time = USEC_INFINITY;
- _cleanup_free_ char* path = NULL, *unit_id = NULL;
+ _cleanup_free_ char *path = NULL, *unit_id = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = acquire_boot_times(bus, &t);
/* outside box, fill */
svg("<rect class=\"box\" x=\"0\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
- SCALE_X * (end - begin), SCALE_Y * height);
+ SCALE_X * (end - begin),
+ SCALE_Y * height);
- for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) {
+ for (i = ((long long) (begin / 100000)) * 100000; i <= end; i += 100000) {
/* lines for each second */
if (i % 5000000 == 0)
svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
- SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
+ SCALE_X * i,
+ SCALE_X * i,
+ SCALE_Y * height,
+ SCALE_X * i,
+ -5.0,
+ 0.000001 * i);
else if (i % 1000000 == 0)
svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
- SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
+ SCALE_X * i,
+ SCALE_X * i,
+ SCALE_Y * height,
+ SCALE_X * i,
+ -5.0,
+ 0.000001 * i);
else
svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- SCALE_X * i, SCALE_X * i, SCALE_Y * height);
+ SCALE_X * i,
+ SCALE_X * i,
+ SCALE_Y * height);
}
}
"<!-- that render these files properly but much slower are ImageMagick, -->\n"
"<!-- gimp, inkscape, etc. To display the files on your system, just -->\n"
"<!-- point your browser to this file. -->\n\n"
- "<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", PACKAGE_VERSION);
+ "<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", GIT_VERSION);
/* style sheet */
svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n"
return 0;
}
-static int list_dependencies_print(const char *name, unsigned level, unsigned branches,
- bool last, struct unit_times *times, struct boot_times *boot) {
+static int list_dependencies_print(
+ const char *name,
+ unsigned level,
+ unsigned branches,
+ bool last,
+ struct unit_times *times,
+ struct boot_times *boot) {
+
unsigned i;
char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
static Hashmap *unit_times_hashmap;
-static int list_dependencies_compare(char * const *a, char * const *b) {
+static int list_dependencies_compare(char *const *a, char *const *b) {
usec_t usa = 0, usb = 0;
struct unit_times *times;
}
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;
+ return times && times->activated > 0 && times->activated <= boot->finish_time;
}
-static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units,
- unsigned branches) {
+static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units, unsigned branches) {
_cleanup_strv_free_ char **deps = NULL;
char **c;
int r = 0;
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times_in_range(times, boot) &&
- times->activated >= service_longest)
+ if (times_in_range(times, boot) && times->activated >= service_longest)
service_longest = times->activated;
}
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times_in_range(times, boot) &&
- 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_in_range(times, boot) ||
- service_longest - times->activated > arg_fuzz)
+ if (!times_in_range(times, boot) || service_longest - times->activated > arg_fuzz)
continue;
to_print--;
continue;
}
- r = list_dependencies_one(bus, *c, level + 1, units,
- (branches << 1) | (to_print ? 1 : 0));
+ r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (to_print ? 1 : 0));
if (r < 0)
return r;
(void) pager_open(arg_pager_flags);
- 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");
+ puts("The time when unit became active or started is printed after the \"@\" character.\n"
+ "The time the unit took to start is printed after the \"+\" character.\n");
if (argc > 1) {
char **name;
return 0;
}
-static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, const char *color, char* patterns[], char* from_patterns[], char* to_patterns[]) {
+static int graph_one_property(
+ sd_bus *bus,
+ const UnitInfo *u,
+ const char *prop,
+ const char *color,
+ char *patterns[],
+ char *from_patterns[],
+ char *to_patterns[]) {
+
_cleanup_strv_free_ char **units = NULL;
char **unit;
int r;
match_patterns = strv_fnmatch(patterns, u->id, 0);
- if (!strv_isempty(from_patterns) &&
- !match_patterns &&
- !strv_fnmatch(from_patterns, u->id, 0))
- return 0;
+ if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id, 0))
+ return 0;
r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
if (r < 0)
match_patterns2 = strv_fnmatch(patterns, *unit, 0);
- if (!strv_isempty(to_patterns) &&
- !match_patterns2 &&
- !strv_fnmatch(to_patterns, *unit, 0))
+ if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit, 0))
continue;
if (!strv_isempty(patterns) && !match_patterns && !match_patterns2)
if (r < 0) {
/* fall back to Dump if DumpByFileDescriptor is not supported */
if (!IN_SET(r, -EACCES, -EBADR))
- return log_error_errno(r, "Failed to issue method call DumpByFileDescriptor: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to issue method call DumpByFileDescriptor: %s",
+ bus_error_message(&error, r));
return dump_fallback(bus);
}
if (!t)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Path %s does not start with any known prefix.",
- *arg);
+ "Path %s does not start with any known prefix.", *arg);
} else
t = *arg;
_cleanup_fclose_ FILE *f = NULL;
int r;
- /* Let's read the available system calls from the list of available tracing events. Slightly dirty, but good
- * enough for analysis purposes. */
-
- f = fopen("/sys/kernel/debug/tracing/available_events", "re");
- if (!f)
- return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno, "Can't read open /sys/kernel/debug/tracing/available_events: %m");
+ /* Let's read the available system calls from the list of available tracing events. Slightly dirty,
+ * but good enough for analysis purposes. */
+
+ f = fopen("/sys/kernel/tracing/available_events", "re");
+ if (!f) {
+ /* We tried the non-debugfs mount point and that didn't work. If it wasn't mounted, maybe the
+ * old debugfs mount point works? */
+ f = fopen("/sys/kernel/debug/tracing/available_events", "re");
+ if (!f)
+ return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno,
+ "Can't read open tracefs' available_events file: %m");
+ }
for (;;) {
_cleanup_free_ char *line = NULL;
if (!e)
continue;
- /* These are named differently inside the kernel than their external name for historical reasons. Let's hide them here. */
+ /* These are named differently inside the kernel than their external name for historical
+ * reasons. Let's hide them here. */
if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
continue;
set->help);
NULSTR_FOREACH(syscall, set->value)
- printf(" %s%s%s\n",
- syscall[0] == '@' ? ansi_underline() : "",
- syscall,
- ansi_normal());
+ printf(" %s%s%s\n", syscall[0] == '@' ? ansi_underline() : "", syscall, ansi_normal());
}
static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
/* make sure the error appears below normal output */
fflush(stdout);
- log_error("Filter set \"%s\" not found.", *name);
- return -ENOENT;
+ return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+ "Filter set \"%s\" not found.", *name);
}
dump_syscall_filter(set);
#else
static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
- "Not compiled with syscall filters, sorry.");
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not compiled with syscall filters, sorry.");
}
#endif
+static void parsing_hint(const char *p, bool calendar, bool timestamp, bool timespan) {
+ if (calendar && calendar_spec_from_string(p, NULL) >= 0)
+ log_notice("Hint: this expression is a valid calendar specification. "
+ "Use 'systemd-analyze calendar \"%s\"' instead?", p);
+ if (timestamp && parse_timestamp(p, NULL) >= 0)
+ log_notice("Hint: this expression is a valid timestamp. "
+ "Use 'systemd-analyze timestamp \"%s\"' instead?", p);
+ if (timespan && parse_time(p, NULL, USEC_PER_SEC) >= 0)
+ log_notice("Hint: this expression is a valid timespan. "
+ "Use 'systemd-analyze timespan \"%s\"' instead?", p);
+}
+
static int dump_timespan(int argc, char *argv[], void *userdata) {
char **input_timespan;
char ft_buf[FORMAT_TIMESPAN_MAX];
r = parse_time(*input_timespan, &output_usecs, USEC_PER_SEC);
- if (r < 0)
- return log_error_errno(r, "Failed to parse time span '%s': %m", *input_timespan);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse time span '%s': %m", *input_timespan);
+ parsing_hint(*input_timespan, true, true, false);
+ return r;
+ }
printf("Original: %s\n", *input_timespan);
printf(" %ss: %" PRIu64 "\n", special_glyph(SPECIAL_GLYPH_MU), output_usecs);
- printf(" Human: %s\n", format_timespan(ft_buf, sizeof(ft_buf), output_usecs, usec_magnitude));
+ printf(" Human: %s%s%s\n",
+ ansi_highlight(),
+ format_timespan(ft_buf, sizeof(ft_buf), output_usecs, usec_magnitude),
+ ansi_normal());
if (input_timespan[1])
putchar('\n');
return EXIT_SUCCESS;
}
-static int test_calendar(int argc, char *argv[], void *userdata) {
+static int test_timestamp_one(const char *p) {
+ usec_t usec;
+ char buf[FORMAT_TIMESTAMP_MAX];
+ int r;
+
+ r = parse_timestamp(p, &usec);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse \"%s\": %m", p);
+ parsing_hint(p, true, false, true);
+ return r;
+ }
+
+ printf(" Original form: %s\n", p);
+ printf("Normalized form: %s%s%s\n",
+ ansi_highlight_blue(),
+ format_timestamp(buf, sizeof buf, usec),
+ ansi_normal());
+
+ if (!in_utc_timezone())
+ printf(" (in UTC): %s\n", format_timestamp_utc(buf, sizeof buf, usec));
+
+ printf(" From now: %s\n", format_timestamp_relative(buf, sizeof buf, usec));
+
+ return 0;
+}
+
+static int test_timestamp(int argc, char *argv[], void *userdata) {
int ret = 0, r;
char **p;
- usec_t n;
-
- n = now(CLOCK_REALTIME);
STRV_FOREACH(p, strv_skip(argv, 1)) {
- _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
- _cleanup_free_ char *t = NULL;
+ r = test_timestamp_one(*p);
+ if (ret == 0 && r < 0)
+ ret = r;
+
+ if (*(p + 1))
+ putchar('\n');
+ }
+
+ return ret;
+}
+
+static int test_calendar_one(usec_t n, const char *p) {
+ _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ r = calendar_spec_from_string(p, &spec);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse calendar specification '%s': %m", p);
+ parsing_hint(p, false, true, true);
+ return r;
+ }
+
+ r = calendar_spec_to_string(spec, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to format calendar specification '%s': %m", p);
+
+ if (!streq(t, p))
+ printf(" Original form: %s\n", p);
+
+ printf("Normalized form: %s\n", t);
+
+ for (unsigned i = 0; i < arg_iterations; i++) {
+ char buffer[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESTAMP_RELATIVE_MAX)];
usec_t next;
- r = calendar_spec_from_string(*p, &spec);
- if (r < 0) {
- ret = log_error_errno(r, "Failed to parse calendar specification '%s': %m", *p);
- continue;
+ r = calendar_spec_next_usec(spec, n, &next);
+ if (r == -ENOENT) {
+ if (i == 0)
+ printf(" Next elapse: %snever%s\n", ansi_highlight_yellow(), ansi_normal());
+ return 0;
}
-
- r = calendar_spec_normalize(spec);
- if (r < 0) {
- ret = log_error_errno(r, "Failed to normalize calendar specification '%s': %m", *p);
- continue;
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine next elapse for '%s': %m", p);
+
+ if (i == 0)
+ printf(" Next elapse: %s%s%s\n",
+ ansi_highlight_blue(),
+ format_timestamp(buffer, sizeof(buffer), next),
+ ansi_normal());
+ else {
+ int k = DECIMAL_STR_WIDTH(i + 1);
+
+ if (k < 8)
+ k = 8 - k;
+ else
+ k = 0;
+
+ printf("%*sIter. #%u: %s%s%s\n",
+ k, "", i+1,
+ ansi_highlight_blue(), format_timestamp(buffer, sizeof(buffer), next), ansi_normal());
}
- r = calendar_spec_to_string(spec, &t);
- if (r < 0) {
- ret = log_error_errno(r, "Failed to format calendar specification '%s': %m", *p);
- continue;
- }
+ if (!in_utc_timezone())
+ printf(" (in UTC): %s\n", format_timestamp_utc(buffer, sizeof(buffer), next));
- if (!streq(t, *p))
- printf(" Original form: %s\n", *p);
+ printf(" From now: %s\n", format_timestamp_relative(buffer, sizeof(buffer), next));
- printf("Normalized form: %s\n", t);
+ n = next;
+ }
- r = calendar_spec_next_usec(spec, n, &next);
- if (r == -ENOENT)
- printf(" Next elapse: never\n");
- else if (r < 0) {
- ret = log_error_errno(r, "Failed to determine next elapse for '%s': %m", *p);
- continue;
- } else {
- char buffer[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESTAMP_RELATIVE_MAX)];
+ return 0;
+}
- printf(" Next elapse: %s\n", format_timestamp(buffer, sizeof(buffer), next));
+static int test_calendar(int argc, char *argv[], void *userdata) {
+ int ret = 0, r;
+ char **p;
+ usec_t n;
- if (!in_utc_timezone())
- printf(" (in UTC): %s\n", format_timestamp_utc(buffer, sizeof(buffer), next));
+ n = now(CLOCK_REALTIME); /* We want to use the same "base" for all expressions */
- printf(" From now: %s\n", format_timestamp_relative(buffer, sizeof(buffer), next));
- }
+ STRV_FOREACH(p, strv_skip(argv, 1)) {
+ r = test_calendar_one(n, *p);
+ if (ret == 0 && r < 0)
+ ret = r;
- if (*(p+1))
+ if (*(p + 1))
putchar('\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"
+ " --fuzz=SECONDS Also print services which finished SECONDS earlier\n"
+ " than the latest in the branch\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"
" 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"
+ " 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"
"\nSee the %s for details.\n"
, link
);
- /* When updating this list, including descriptions, apply changes to shell-completion/bash/systemd-analyze and
- * shell-completion/zsh/_systemd-analyze too. */
+ /* When updating this list, including descriptions, apply changes to
+ * shell-completion/bash/systemd-analyze and shell-completion/zsh/_systemd-analyze too. */
return 0;
}
ARG_NO_PAGER,
ARG_MAN,
ARG_GENERATORS,
+ ARG_ITERATIONS,
};
static const struct option options[] = {
{ "generators", optional_argument, NULL, ARG_GENERATORS },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
+ { "iterations", required_argument, NULL, ARG_ITERATIONS },
{}
};
break;
+ case ARG_ITERATIONS:
+ r = safe_atou(optarg, &arg_iterations);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse iterations: %s", optarg);
+
+ break;
+
case '?':
return -EINVAL;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --global only makes sense with verbs dot, unit-paths, verify.");
+ if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Option --user is not supported for cat-config right now.");
+
if (arg_root && !streq_ptr(argv[optind], "cat-config"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --root is only supported for cat-config right now.");
{ "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 },
+ { "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 },
{}
};
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */
+ log_show_color(true);
log_parse_environment();
log_open();