mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
analyze: extend the dump command to accept patterns
The new function DumpPatterns() can be used to limit (drastically) the size of the data returned by PID1. Hence the optimization of serializing data into a file descriptor should be less relevant than having the possibility to limit the data when communicating with the service manager remotely. NB: when passing patterns, the dump command omits the version of the manager as well as the features and the timestamps.
This commit is contained in:
parent
17f6406bf2
commit
d1d8786c5b
@ -162,6 +162,8 @@ node /org/freedesktop/systemd1 {
|
|||||||
Subscribe();
|
Subscribe();
|
||||||
Unsubscribe();
|
Unsubscribe();
|
||||||
Dump(out s output);
|
Dump(out s output);
|
||||||
|
DumpPatterns(in as patterns,
|
||||||
|
out s output);
|
||||||
DumpByFileDescriptor(out h fd);
|
DumpByFileDescriptor(out h fd);
|
||||||
Reload();
|
Reload();
|
||||||
@org.freedesktop.DBus.Method.NoReply("true")
|
@org.freedesktop.DBus.Method.NoReply("true")
|
||||||
@ -868,6 +870,8 @@ node /org/freedesktop/systemd1 {
|
|||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="Dump()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="Dump()"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-method" generated="True" extra-ref="DumpPatterns()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="DumpByFileDescriptor()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="DumpByFileDescriptor()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="Reload()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="Reload()"/>
|
||||||
@ -1338,7 +1342,9 @@ node /org/freedesktop/systemd1 {
|
|||||||
string guaranteed, and new fields may be added any time, and old fields removed. The general structure
|
string guaranteed, and new fields may be added any time, and old fields removed. The general structure
|
||||||
may be rearranged drastically between releases. This is exposed by
|
may be rearranged drastically between releases. This is exposed by
|
||||||
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||||
<command>dump</command> command. The <function>DumpByFileDescriptor()</function> method is identical to
|
<command>dump</command> command. Similarly, <function>DumpPatterns()</function> returns the internal
|
||||||
|
state of units whose names match the glob expressions specified in the <varname>patterns</varname>
|
||||||
|
argument. The <function>DumpByFileDescriptor()</function> method is identical to
|
||||||
<function>Dump()</function> but returns the data serialized into a file descriptor (the client should
|
<function>Dump()</function> but returns the data serialized into a file descriptor (the client should
|
||||||
read the text data from it until hitting EOF). Given the size limits on D-Bus messages and the possibly
|
read the text data from it until hitting EOF). Given the size limits on D-Bus messages and the possibly
|
||||||
large size of the returned string, <function>DumpByFileDescriptor()</function> is usually the
|
large size of the returned string, <function>DumpByFileDescriptor()</function> is usually the
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
<command>systemd-analyze</command>
|
<command>systemd-analyze</command>
|
||||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||||
<arg choice="plain">dump</arg>
|
<arg choice="plain">dump</arg>
|
||||||
|
<arg choice="opt" rep="repeat"><replaceable>PATTERN</replaceable></arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
|
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
@ -243,10 +244,12 @@ multi-user.target @47.820s
|
|||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title><command>systemd-analyze dump</command></title>
|
<title><command>systemd-analyze dump [<replaceable>pattern</replaceable>…]</command></title>
|
||||||
|
|
||||||
<para>This command outputs a (usually very long) human-readable serialization of the complete server
|
<para>Without any parameter, this command outputs a (usually very long) human-readable serialization of
|
||||||
state. Its format is subject to change without notice and should not be parsed by applications.</para>
|
the complete service manager state. Optional glob pattern may be specified, causing the output to be
|
||||||
|
limited to units whose names match one of the patterns. The output format is subject to change without
|
||||||
|
notice and should not be parsed by applications.</para>
|
||||||
|
|
||||||
<example>
|
<example>
|
||||||
<title>Show the internal state of user manager</title>
|
<title>Show the internal state of user manager</title>
|
||||||
|
@ -60,9 +60,10 @@ _systemd_analyze() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
local -A VERBS=(
|
local -A VERBS=(
|
||||||
[STANDALONE]='time blame plot dump unit-paths exit-status calendar timestamp timespan'
|
[STANDALONE]='time blame plot unit-paths exit-status calendar timestamp timespan'
|
||||||
[CRITICAL_CHAIN]='critical-chain'
|
[CRITICAL_CHAIN]='critical-chain'
|
||||||
[DOT]='dot'
|
[DOT]='dot'
|
||||||
|
[DUMP]='dump'
|
||||||
[VERIFY]='verify'
|
[VERIFY]='verify'
|
||||||
[SECCOMP_FILTER]='syscall-filter'
|
[SECCOMP_FILTER]='syscall-filter'
|
||||||
[CAT_CONFIG]='cat-config'
|
[CAT_CONFIG]='cat-config'
|
||||||
@ -125,6 +126,13 @@ _systemd_analyze() {
|
|||||||
comps='--help --version --system --user --global --from-pattern --to-pattern --order --require'
|
comps='--help --version --system --user --global --from-pattern --to-pattern --order --require'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
elif __contains_word "$verb" ${VERBS[DUMP]}; then
|
||||||
|
if [[ $cur = -* ]]; then
|
||||||
|
comps='--help --version --system --user --no-pager'
|
||||||
|
else
|
||||||
|
comps=$( __get_units_all )
|
||||||
|
fi
|
||||||
|
|
||||||
elif __contains_word "$verb" ${VERBS[SECCOMP_FILTER]}; then
|
elif __contains_word "$verb" ${VERBS[SECCOMP_FILTER]}; then
|
||||||
if [[ $cur = -* ]]; then
|
if [[ $cur = -* ]]; then
|
||||||
comps='--help --version --no-pager'
|
comps='--help --version --no-pager'
|
||||||
|
@ -29,6 +29,46 @@ static int dump_fallback(sd_bus *bus) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dump_patterns(sd_bus *bus, char **patterns) {
|
||||||
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
|
||||||
|
_cleanup_strv_free_ char **mangled = NULL;
|
||||||
|
const char *text;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "DumpPatterns");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
STRV_FOREACH(pattern, patterns) {
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
r = unit_name_mangle_with_suffix(*pattern, NULL, UNIT_NAME_MANGLE_GLOB, ".service", &t);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to mangle name: %m");
|
||||||
|
|
||||||
|
r = strv_consume(&mangled, t);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_append_strv(m, mangled);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_call(bus, m, 0, &error, &reply);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to issue method call DumpPatterns: %s",
|
||||||
|
bus_error_message(&error, r));
|
||||||
|
|
||||||
|
r = sd_bus_message_read(reply, "s", &text);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
|
fputs(text, stdout);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int verb_dump(int argc, char *argv[], void *userdata) {
|
int verb_dump(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
_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_message_unrefp) sd_bus_message *reply = NULL;
|
||||||
@ -42,6 +82,9 @@ int verb_dump(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
pager_open(arg_pager_flags);
|
pager_open(arg_pager_flags);
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
return dump_patterns(bus, strv_skip(argv, 1));
|
||||||
|
|
||||||
if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD))
|
if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD))
|
||||||
return dump_fallback(bus);
|
return dump_fallback(bus);
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||||||
" plot Output SVG graphic showing service\n"
|
" plot Output SVG graphic showing service\n"
|
||||||
" initialization\n"
|
" initialization\n"
|
||||||
" dot [UNIT...] Output dependency graph in %s format\n"
|
" dot [UNIT...] Output dependency graph in %s format\n"
|
||||||
" dump Output state serialization of service\n"
|
" dump [PATTERN...] Output state serialization of service\n"
|
||||||
" manager\n"
|
" manager\n"
|
||||||
" cat-config Show configuration file and drop-ins\n"
|
" cat-config Show configuration file and drop-ins\n"
|
||||||
" unit-files List files and symlinks for units\n"
|
" unit-files List files and symlinks for units\n"
|
||||||
@ -557,7 +557,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
{ "get-log-target", VERB_ANY, 1, 0, verb_log_control },
|
{ "get-log-target", VERB_ANY, 1, 0, verb_log_control },
|
||||||
{ "service-watchdogs", VERB_ANY, 2, 0, verb_service_watchdogs },
|
{ "service-watchdogs", VERB_ANY, 2, 0, verb_service_watchdogs },
|
||||||
/* ↑ … until here ↑ */
|
/* ↑ … until here ↑ */
|
||||||
{ "dump", VERB_ANY, 1, 0, verb_dump },
|
{ "dump", VERB_ANY, VERB_ANY, 0, verb_dump },
|
||||||
{ "cat-config", 2, VERB_ANY, 0, verb_cat_config },
|
{ "cat-config", 2, VERB_ANY, 0, verb_cat_config },
|
||||||
{ "unit-files", VERB_ANY, VERB_ANY, 0, verb_unit_files },
|
{ "unit-files", VERB_ANY, VERB_ANY, 0, verb_unit_files },
|
||||||
{ "unit-paths", 1, 1, 0, verb_unit_paths },
|
{ "unit-paths", 1, 1, 0, verb_unit_paths },
|
||||||
|
@ -1344,7 +1344,13 @@ static int method_unsubscribe(sd_bus_message *message, void *userdata, sd_bus_er
|
|||||||
return sd_bus_reply_method_return(message, NULL);
|
return sd_bus_reply_method_return(message, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_impl(sd_bus_message *message, void *userdata, sd_bus_error *error, int (*reply)(sd_bus_message *, char *)) {
|
static int dump_impl(
|
||||||
|
sd_bus_message *message,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error,
|
||||||
|
char **patterns,
|
||||||
|
int (*reply)(sd_bus_message *, char *)) {
|
||||||
|
|
||||||
_cleanup_free_ char *dump = NULL;
|
_cleanup_free_ char *dump = NULL;
|
||||||
Manager *m = ASSERT_PTR(userdata);
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
int r;
|
int r;
|
||||||
@ -1357,7 +1363,7 @@ static int dump_impl(sd_bus_message *message, void *userdata, sd_bus_error *erro
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = manager_get_dump_string(m, &dump);
|
r = manager_get_dump_string(m, patterns, &dump);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1369,7 +1375,7 @@ static int reply_dump(sd_bus_message *message, char *dump) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
return dump_impl(message, userdata, error, reply_dump);
|
return dump_impl(message, userdata, error, NULL, reply_dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
|
static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
|
||||||
@ -1383,7 +1389,18 @@ static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
static int method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
return dump_impl(message, userdata, error, reply_dump_by_fd);
|
return dump_impl(message, userdata, error, NULL, reply_dump_by_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int method_dump_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
|
_cleanup_strv_free_ char **patterns = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = sd_bus_message_read_strv(message, &patterns);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return dump_impl(message, userdata, error, patterns, reply_dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
@ -3010,6 +3027,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||||||
SD_BUS_RESULT("s", output),
|
SD_BUS_RESULT("s", output),
|
||||||
method_dump,
|
method_dump,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD_WITH_ARGS("DumpPatterns",
|
||||||
|
SD_BUS_ARGS("as", patterns),
|
||||||
|
SD_BUS_RESULT("s", output),
|
||||||
|
method_dump_patterns,
|
||||||
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD_WITH_ARGS("DumpByFileDescriptor",
|
SD_BUS_METHOD_WITH_ARGS("DumpByFileDescriptor",
|
||||||
SD_BUS_NO_ARGS,
|
SD_BUS_NO_ARGS,
|
||||||
SD_BUS_RESULT("h", fd),
|
SD_BUS_RESULT("h", fd),
|
||||||
|
@ -919,7 +919,7 @@ static int ask_for_confirmation(const ExecContext *context, const char *vc, Unit
|
|||||||
u->id, u->description, cmdline);
|
u->id, u->description, cmdline);
|
||||||
continue; /* ask again */
|
continue; /* ask again */
|
||||||
case 'j':
|
case 'j':
|
||||||
manager_dump_jobs(u->manager, stdout, " ");
|
manager_dump_jobs(u->manager, stdout, /* patterns= */ NULL, " ");
|
||||||
continue; /* ask again */
|
continue; /* ask again */
|
||||||
case 'n':
|
case 'n':
|
||||||
/* 'n' was removed in favor of 'f'. */
|
/* 'n' was removed in favor of 'f'. */
|
||||||
|
@ -83,7 +83,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
assert_se(g);
|
assert_se(g);
|
||||||
|
|
||||||
unit_dump(u, g, "");
|
unit_dump(u, g, "");
|
||||||
manager_dump(m, g, ">>>");
|
manager_dump(m, g, /* patterns= */ NULL, ">>>");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -7,31 +7,40 @@
|
|||||||
#include "manager-dump.h"
|
#include "manager-dump.h"
|
||||||
#include "unit-serialize.h"
|
#include "unit-serialize.h"
|
||||||
|
|
||||||
void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
|
void manager_dump_jobs(Manager *s, FILE *f, char **patterns, const char *prefix) {
|
||||||
Job *j;
|
Job *j;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(f);
|
assert(f);
|
||||||
|
|
||||||
HASHMAP_FOREACH(j, s->jobs)
|
HASHMAP_FOREACH(j, s->jobs) {
|
||||||
|
|
||||||
|
if (!strv_fnmatch_or_empty(patterns, j->unit->id, FNM_NOESCAPE))
|
||||||
|
continue;
|
||||||
|
|
||||||
job_dump(j, f, prefix);
|
job_dump(j, f, prefix);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
|
void manager_dump_units(Manager *s, FILE *f, char **patterns, const char *prefix) {
|
||||||
Unit *u;
|
Unit *u;
|
||||||
const char *t;
|
const char *t;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(f);
|
assert(f);
|
||||||
|
|
||||||
HASHMAP_FOREACH_KEY(u, t, s->units)
|
HASHMAP_FOREACH_KEY(u, t, s->units) {
|
||||||
if (u->id == t)
|
if (u->id != t)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
|
||||||
|
continue;
|
||||||
|
|
||||||
unit_dump(u, f, prefix);
|
unit_dump(u, f, prefix);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void manager_dump(Manager *m, FILE *f, const char *prefix) {
|
static void manager_dump_header(Manager *m, FILE *f, const char *prefix) {
|
||||||
assert(m);
|
|
||||||
assert(f);
|
|
||||||
|
|
||||||
/* NB: this is a debug interface for developers. It's not supposed to be machine readable or be
|
/* NB: this is a debug interface for developers. It's not supposed to be machine readable or be
|
||||||
* stable between versions. We take the liberty to restructure it entirely between versions and
|
* stable between versions. We take the liberty to restructure it entirely between versions and
|
||||||
@ -50,12 +59,22 @@ void manager_dump(Manager *m, FILE *f, const char *prefix) {
|
|||||||
timestamp_is_set(t->realtime) ? FORMAT_TIMESTAMP(t->realtime) :
|
timestamp_is_set(t->realtime) ? FORMAT_TIMESTAMP(t->realtime) :
|
||||||
FORMAT_TIMESPAN(t->monotonic, 1));
|
FORMAT_TIMESPAN(t->monotonic, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
manager_dump_units(m, f, prefix);
|
|
||||||
manager_dump_jobs(m, f, prefix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int manager_get_dump_string(Manager *m, char **ret) {
|
void manager_dump(Manager *m, FILE *f, char **patterns, const char *prefix) {
|
||||||
|
assert(m);
|
||||||
|
assert(f);
|
||||||
|
|
||||||
|
/* If no pattern is provided, dump the full manager state including the manager version, features and
|
||||||
|
* so on. Otherwise limit the dump to the units/jobs matching the specified patterns. */
|
||||||
|
if (!patterns)
|
||||||
|
manager_dump_header(m, f, prefix);
|
||||||
|
|
||||||
|
manager_dump_units(m, f, patterns, prefix);
|
||||||
|
manager_dump_jobs(m, f, patterns, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
int manager_get_dump_string(Manager *m, char **patterns, char **ret) {
|
||||||
_cleanup_free_ char *dump = NULL;
|
_cleanup_free_ char *dump = NULL;
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -68,7 +87,7 @@ int manager_get_dump_string(Manager *m, char **ret) {
|
|||||||
if (!f)
|
if (!f)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
manager_dump(m, f, NULL);
|
manager_dump(m, f, patterns, NULL);
|
||||||
|
|
||||||
r = fflush_and_check(f);
|
r = fflush_and_check(f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -85,8 +104,8 @@ void manager_test_summary(Manager *m) {
|
|||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
printf("-> By units:\n");
|
printf("-> By units:\n");
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("-> By jobs:\n");
|
printf("-> By jobs:\n");
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
|
||||||
void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
|
void manager_dump_jobs(Manager *s, FILE *f, char **patterns, const char *prefix);
|
||||||
void manager_dump_units(Manager *s, FILE *f, const char *prefix);
|
void manager_dump_units(Manager *s, FILE *f, char **patterns, const char *prefix);
|
||||||
void manager_dump(Manager *s, FILE *f, const char *prefix);
|
void manager_dump(Manager *s, FILE *f, char **patterns, const char *prefix);
|
||||||
int manager_get_dump_string(Manager *m, char **ret);
|
int manager_get_dump_string(Manager *m, char **patterns, char **ret);
|
||||||
void manager_test_summary(Manager *m);
|
void manager_test_summary(Manager *m);
|
||||||
|
@ -2823,7 +2823,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
|
|||||||
case SIGUSR2: {
|
case SIGUSR2: {
|
||||||
_cleanup_free_ char *dump = NULL;
|
_cleanup_free_ char *dump = NULL;
|
||||||
|
|
||||||
r = manager_get_dump_string(m, &dump);
|
r = manager_get_dump_string(m, /* patterns= */ NULL, &dump);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_warning_errno(errno, "Failed to acquire manager dump: %m");
|
log_warning_errno(errno, "Failed to acquire manager dump: %m");
|
||||||
break;
|
break;
|
||||||
|
@ -120,6 +120,10 @@
|
|||||||
send_interface="org.freedesktop.systemd1.Manager"
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
send_member="DumpByFileDescriptor"/>
|
send_member="DumpByFileDescriptor"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
|
send_member="DumpPatterns"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.systemd1"
|
<allow send_destination="org.freedesktop.systemd1"
|
||||||
send_interface="org.freedesktop.systemd1.Manager"
|
send_interface="org.freedesktop.systemd1.Manager"
|
||||||
send_member="ListUnitFiles"/>
|
send_member="ListUnitFiles"/>
|
||||||
|
@ -103,86 +103,86 @@ int main(int argc, char *argv[]) {
|
|||||||
assert_se(manager_load_startable_unit_or_warn(m, "a.service", NULL, &a) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "a.service", NULL, &a) >= 0);
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "b.service", NULL, &b) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "b.service", NULL, &b) >= 0);
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "c.service", NULL, &c) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "c.service", NULL, &c) >= 0);
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test1: (Trivial)\n");
|
printf("Test1: (Trivial)\n");
|
||||||
r = manager_add_job(m, JOB_START, c, JOB_REPLACE, NULL, &err, &j);
|
r = manager_add_job(m, JOB_START, c, JOB_REPLACE, NULL, &err, &j);
|
||||||
if (sd_bus_error_is_set(&err))
|
if (sd_bus_error_is_set(&err))
|
||||||
log_error("error: %s: %s", err.name, err.message);
|
log_error("error: %s: %s", err.name, err.message);
|
||||||
assert_se(r == 0);
|
assert_se(r == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Load2:\n");
|
printf("Load2:\n");
|
||||||
manager_clear_jobs(m);
|
manager_clear_jobs(m);
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "d.service", NULL, &d) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "d.service", NULL, &d) >= 0);
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "e.service", NULL, &e) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "e.service", NULL, &e) >= 0);
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test2: (Cyclic Order, Unfixable)\n");
|
printf("Test2: (Cyclic Order, Unfixable)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
|
assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
|
printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, NULL, &j) == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test4: (Identical transaction)\n");
|
printf("Test4: (Identical transaction)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Load3:\n");
|
printf("Load3:\n");
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "g.service", NULL, &g) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "g.service", NULL, &g) >= 0);
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test5: (Colliding transaction, fail)\n");
|
printf("Test5: (Colliding transaction, fail)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
|
assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
|
||||||
|
|
||||||
printf("Test6: (Colliding transaction, replace)\n");
|
printf("Test6: (Colliding transaction, replace)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, NULL, &j) == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test7: (Unmergeable job type, fail)\n");
|
printf("Test7: (Unmergeable job type, fail)\n");
|
||||||
assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
|
assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
|
||||||
|
|
||||||
printf("Test8: (Mergeable job type, fail)\n");
|
printf("Test8: (Mergeable job type, fail)\n");
|
||||||
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test9: (Unmergeable job type, replace)\n");
|
printf("Test9: (Unmergeable job type, replace)\n");
|
||||||
assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, NULL, &j) == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Load4:\n");
|
printf("Load4:\n");
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "h.service", NULL, &h) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "h.service", NULL, &h) >= 0);
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
|
printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Load5:\n");
|
printf("Load5:\n");
|
||||||
manager_clear_jobs(m);
|
manager_clear_jobs(m);
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "i.service", NULL, &i) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "i.service", NULL, &i) >= 0);
|
||||||
SERVICE(a)->state = SERVICE_RUNNING;
|
SERVICE(a)->state = SERVICE_RUNNING;
|
||||||
SERVICE(d)->state = SERVICE_RUNNING;
|
SERVICE(d)->state = SERVICE_RUNNING;
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test11: (Start/stop job ordering, execution cycle)\n");
|
printf("Test11: (Start/stop job ordering, execution cycle)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, i, JOB_FAIL, NULL, NULL, &j) == 0);
|
assert_se(manager_add_job(m, JOB_START, i, JOB_FAIL, NULL, NULL, &j) == 0);
|
||||||
assert_se(unit_has_job_type(a, JOB_STOP));
|
assert_se(unit_has_job_type(a, JOB_STOP));
|
||||||
assert_se(unit_has_job_type(d, JOB_STOP));
|
assert_se(unit_has_job_type(d, JOB_STOP));
|
||||||
assert_se(unit_has_job_type(b, JOB_START));
|
assert_se(unit_has_job_type(b, JOB_START));
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Load6:\n");
|
printf("Load6:\n");
|
||||||
manager_clear_jobs(m);
|
manager_clear_jobs(m);
|
||||||
assert_se(manager_load_startable_unit_or_warn(m, "a-conj.service", NULL, &a_conj) >= 0);
|
assert_se(manager_load_startable_unit_or_warn(m, "a-conj.service", NULL, &a_conj) >= 0);
|
||||||
SERVICE(a)->state = SERVICE_DEAD;
|
SERVICE(a)->state = SERVICE_DEAD;
|
||||||
manager_dump_units(m, stdout, "\t");
|
manager_dump_units(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
printf("Test12: (Trivial cycle, Unfixable)\n");
|
printf("Test12: (Trivial cycle, Unfixable)\n");
|
||||||
assert_se(manager_add_job(m, JOB_START, a_conj, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
|
assert_se(manager_add_job(m, JOB_START, a_conj, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
|
||||||
manager_dump_jobs(m, stdout, "\t");
|
manager_dump_jobs(m, stdout, /* patterns= */ NULL, "\t");
|
||||||
|
|
||||||
assert_se(!hashmap_get(unit_get_dependencies(a, UNIT_PROPAGATES_RELOAD_TO), b));
|
assert_se(!hashmap_get(unit_get_dependencies(a, UNIT_PROPAGATES_RELOAD_TO), b));
|
||||||
assert_se(!hashmap_get(unit_get_dependencies(b, UNIT_RELOAD_PROPAGATED_FROM), a));
|
assert_se(!hashmap_get(unit_get_dependencies(b, UNIT_RELOAD_PROPAGATED_FROM), a));
|
||||||
|
Loading…
Reference in New Issue
Block a user