X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=3248f512bf305ddf0bec4498f0665a2edc99c8f4;hp=1d119c991226214050f1afae6434e0a7a9f97a4e;hb=d8fba7c6ccea5e60f31f329f481fb2cdf6907ce9;hpb=cc3f2093f622c04d12d287689d37d861ded41360 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 1d119c991..3248f512b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "sd-daemon.h" #include "sd-shutdown.h" @@ -82,6 +83,7 @@ static enum dependency { DEPENDENCY_REVERSE, DEPENDENCY_AFTER, DEPENDENCY_BEFORE, + _DEPENDENCY_MAX } arg_dependency = DEPENDENCY_FORWARD; static const char *arg_job_mode = "replace"; static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; @@ -139,6 +141,12 @@ static int halt_now(enum action a); static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); +static char** strv_skip_first(char **strv) { + if (strv_length(strv) > 0) + return strv + 1; + return NULL; +} + static void pager_open_if_enabled(void) { if (arg_no_pager) @@ -279,7 +287,7 @@ static int compare_unit_info(const void *a, const void *b) { return strcasecmp(u->id, v->id); } -static bool output_show_unit(const UnitInfo *u) { +static bool output_show_unit(const UnitInfo *u, char **patterns) { const char *dot; if (!strv_isempty(arg_states)) @@ -288,13 +296,22 @@ static bool output_show_unit(const UnitInfo *u) { strv_contains(arg_states, u->sub_state) || strv_contains(arg_states, u->active_state); + if (!strv_isempty(patterns)) { + char **pattern; + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, u->id, FNM_NOESCAPE) == 0) + return true; + return false; + } + return (!arg_types || ((dot = strrchr(u->id, '.')) && strv_find(arg_types, dot+1))) && (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0); } -static void output_units_list(const UnitInfo *unit_infos, unsigned c) { +static void output_units_list(const UnitInfo *unit_infos, unsigned c, char** patterns) { unsigned id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len; const UnitInfo *u; unsigned n_shown = 0; @@ -308,7 +325,7 @@ static void output_units_list(const UnitInfo *unit_infos, unsigned c) { desc_len = 0; for (u = unit_infos; u < unit_infos + c; u++) { - if (!output_show_unit(u)) + if (!output_show_unit(u, patterns)) continue; max_id_len = MAX(max_id_len, strlen(u->id)); @@ -357,7 +374,7 @@ static void output_units_list(const UnitInfo *unit_infos, unsigned c) { const char *on_loaded, *off_loaded, *on = ""; const char *on_active, *off_active, *off = ""; - if (!output_show_unit(u)) + if (!output_show_unit(u, patterns)) continue; if (!n_shown && !arg_no_legend) { @@ -503,7 +520,7 @@ static int list_units(sd_bus *bus, char **args) { return r; qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info); - output_units_list(unit_infos, r); + output_units_list(unit_infos, r, strv_skip_first(args)); return 0; } @@ -692,7 +709,7 @@ static int list_sockets(sd_bus *bus, char **args) { _cleanup_strv_free_ char **listening = NULL, **triggered = NULL; int i, c; - if (!output_show_unit(u)) + if (!output_show_unit(u, strv_skip_first(args))) continue; if (!endswith(u->id, ".socket")) @@ -909,7 +926,7 @@ static int list_timers(sd_bus *bus, char **args) { dual_timestamp next; usec_t m; - if (!output_show_unit(u)) + if (!output_show_unit(u, strv_skip_first(args))) continue; if (!endswith(u->id, ".timer")) @@ -979,16 +996,25 @@ static int compare_unit_file_list(const void *a, const void *b) { return r; } - return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path)); + return strcasecmp(basename(u->path), basename(v->path)); } -static bool output_show_unit_file(const UnitFileList *u) { +static bool output_show_unit_file(const UnitFileList *u, char **patterns) { const char *dot; + if (!strv_isempty(patterns)) { + char **pattern; + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, basename(u->path), FNM_NOESCAPE) == 0) + return true; + return false; + } + return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1)); } -static void output_unit_file_list(const UnitFileList *units, unsigned c) { +static void output_unit_file_list(const UnitFileList *units, unsigned c, char **patterns) { unsigned max_id_len, id_cols, state_cols, n_shown = 0; const UnitFileList *u; @@ -996,10 +1022,10 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { state_cols = sizeof("STATE")-1; for (u = units; u < units + c; u++) { - if (!output_show_unit_file(u)) + if (!output_show_unit_file(u, patterns)) continue; - max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path))); + max_id_len = MAX(max_id_len, strlen(basename(u->path))); state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state))); } @@ -1023,7 +1049,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { const char *on, *off; const char *id; - if (!output_show_unit_file(u)) + if (!output_show_unit_file(u, patterns)) continue; n_shown++; @@ -1040,7 +1066,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { } else on = off = ""; - id = path_get_file_name(u->path); + id = basename(u->path); e = arg_full ? NULL : ellipsize(id, id_cols, 33); @@ -1136,7 +1162,7 @@ static int list_unit_files(sd_bus *bus, char **args) { if (c > 0) { qsort(units, c, sizeof(UnitFileList), compare_unit_file_list); - output_unit_file_list(units, c); + output_unit_file_list(units, c, strv_skip_first(args)); } return 0; @@ -1152,7 +1178,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra for (i = level - 1; i >= 0; i--) { len += 2; - if(len > max_len - 3 && !arg_full) { + if (len > max_len - 3 && !arg_full) { printf("%s...\n",max_len % 2 ? "" : " "); return 0; } @@ -1160,7 +1186,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra } len += 2; - if(len > max_len - 3 && !arg_full) { + if (len > max_len - 3 && !arg_full) { printf("%s...\n",max_len % 2 ? "" : " "); return 0; } @@ -1174,7 +1200,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra } n = ellipsize(name, max_len-len, 100); - if(!n) + if (!n) return log_oom(); printf("%s\n", n); @@ -1183,7 +1209,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) { - static const char *dependencies[] = { + static const char *dependencies[_DEPENDENCY_MAX] = { [DEPENDENCY_FORWARD] = "Requires\0" "RequiresOverridable\0" "Requisite\0" @@ -1206,7 +1232,7 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha assert(bus); assert(name); assert(deps); - assert(arg_dependency < ELEMENTSOF(dependencies)); + assert_cc(ELEMENTSOF(dependencies) == _DEPENDENCY_MAX); path = unit_dbus_path_from_name(name); if (!path) @@ -1334,7 +1360,7 @@ static int list_dependencies_one( if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) { r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1)); - if(r < 0) + if (r < 0) return r; } } @@ -1510,7 +1536,7 @@ struct job_info { const char *name, *type, *state; }; -static void output_jobs_list(const struct job_info* jobs, unsigned n) { +static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipped) { unsigned id_len, unit_len, type_len, state_len; const struct job_info *j; const char *on, *off; @@ -1522,7 +1548,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n) { on = ansi_highlight_green(); off = ansi_highlight_off(); - printf("%sNo jobs running.%s\n", on, off); + printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off); return; } @@ -1580,6 +1606,19 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n) { } } +static bool output_show_job(struct job_info *job, char **patterns) { + if (!strv_isempty(patterns)) { + char **pattern; + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, job->name, FNM_NOESCAPE) == 0) + return true; + return false; + } + + return true; +} + static int list_jobs(sd_bus *bus, char **args) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; @@ -1589,6 +1628,7 @@ static int list_jobs(sd_bus *bus, char **args) { unsigned c = 0; uint32_t id; int r; + bool skipped = false; r = sd_bus_call_method( bus, @@ -1609,16 +1649,17 @@ static int list_jobs(sd_bus *bus, char **args) { return bus_log_parse_error(r); while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) { + struct job_info job = { id, name, type, state }; + + if (!output_show_job(&job, strv_skip_first(args))) { + skipped = true; + continue; + } if (!GREEDY_REALLOC(jobs, size, c + 1)) return log_oom(); - jobs[c++] = (struct job_info) { - id, - name, - type, - state - }; + jobs[c++] = job; } if (r < 0) return bus_log_parse_error(r); @@ -1627,7 +1668,7 @@ static int list_jobs(sd_bus *bus, char **args) { if (r < 0) return bus_log_parse_error(r); - output_jobs_list(jobs, c); + output_jobs_list(jobs, c, skipped); return r; } @@ -1814,7 +1855,7 @@ static int wait_for_jobs(sd_bus *bus, Set *s) { return log_oom(); while (!set_isempty(s)) { - for(;;) { + for (;;) { r = sd_bus_process(bus, NULL); if (r < 0) return r; @@ -2144,7 +2185,7 @@ static int start_unit(sd_bus *bus, char **args) { q = start_unit_one(bus, method, *name, mode, &error, s); if (q < 0) { - r = translate_bus_error_to_exit_status(r, &error); + r = translate_bus_error_to_exit_status(q, &error); sd_bus_error_free(&error); } } @@ -2687,7 +2728,7 @@ static void print_status_info( last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir)); - printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", "); + printf("%s%s", basename(*dropin), last ? "\n" : ", "); } } @@ -3604,16 +3645,13 @@ static int show_one( return r; } -static int show_one_by_pid( - const char *verb, +static int get_unit_dbus_path_by_pid( sd_bus *bus, uint32_t pid, - bool *new_line, - bool *ellipsized) { + char **unit) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - const char *path = NULL; int r; r = sd_bus_call_method( @@ -3630,11 +3668,11 @@ static int show_one_by_pid( return r; } - r = sd_bus_message_read(reply, "o", &path); + r = sd_bus_message_read(reply, "o", unit); if (r < 0) return bus_log_parse_error(r); - return show_one(verb, bus, path, false, new_line, ellipsized); + return 0; } static int show_all( @@ -3663,7 +3701,7 @@ static int show_all( for (u = unit_infos; u < unit_infos + c; u++) { _cleanup_free_ char *p = NULL; - if (!output_show_unit(u)) + if (!output_show_unit(u, NULL)) continue; p = unit_dbus_path_from_name(u->id); @@ -3678,6 +3716,87 @@ static int show_all( return 0; } +static int cat(sd_bus *bus, char **args) { + int r = 0; + char **name; + + _cleanup_free_ char *unit = NULL, *n = NULL; + + assert(bus); + assert(args); + + pager_open_if_enabled(); + + STRV_FOREACH(name, args+1) { + _cleanup_free_ char *fragment_path = NULL; + _cleanup_strv_free_ char **dropin_paths = NULL; + sd_bus_error error; + char **path; + + n = unit_name_mangle(*name); + if (!n) + return log_oom(); + + unit = unit_dbus_path_from_name(n); + if (!unit) + return log_oom(); + + if (need_daemon_reload(bus, n) > 0) + log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.", + n, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + unit, + "org.freedesktop.systemd1.Unit", + "FragmentPath", + &error, + &fragment_path); + if (r < 0) { + log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r)); + continue; + } + + r = sd_bus_get_property_strv( + bus, + "org.freedesktop.systemd1", + unit, + "org.freedesktop.systemd1.Unit", + "DropInPaths", + &error, + &dropin_paths); + if (r < 0) { + log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r)); + continue; + } + + if (!isempty(fragment_path)) { + fprintf(stdout, "# %s\n", fragment_path); + fflush(stdout); + r = sendfile_full(STDOUT_FILENO, fragment_path); + if (r < 0) { + log_warning("Failed to cat %s: %s", fragment_path, strerror(-r)); + continue; + } + } + + STRV_FOREACH(path, dropin_paths) { + fprintf(stdout, "%s# %s\n", + isempty(fragment_path) && path == dropin_paths ? "" : "\n", + *path); + fflush(stdout); + r = sendfile_full(STDOUT_FILENO, *path); + if (r < 0) { + log_warning("Failed to cat %s: %s", *path, strerror(-r)); + continue; + } + } + } + + return r; +} + static int show(sd_bus *bus, char **args) { int r, ret = 0; bool show_properties, show_status, new_line = false; @@ -3702,41 +3821,34 @@ static int show(sd_bus *bus, char **args) { ret = show_all(args[0], bus, false, &new_line, &ellipsized); else STRV_FOREACH(name, args+1) { + _cleanup_free_ char *unit = NULL; uint32_t id; if (safe_atou32(*name, &id) < 0) { - _cleanup_free_ char *p = NULL, *n = NULL; + _cleanup_free_ char *n = NULL; /* Interpret as unit name */ n = unit_name_mangle(*name); if (!n) return log_oom(); - p = unit_dbus_path_from_name(n); - if (!p) + unit = unit_dbus_path_from_name(n); + if (!unit) return log_oom(); - r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized); - if (r != 0) - ret = r; - } else if (show_properties) { - _cleanup_free_ char *p = NULL; - /* Interpret as job id */ - if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) + if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0) return log_oom(); - r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized); - if (r != 0) - ret = r; - } else { /* Interpret as PID */ - r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized); - if (r != 0) + r = get_unit_dbus_path_by_pid(bus, id, &unit); + if (r < 0) ret = r; } + + show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized); } if (ellipsized && !arg_quiet) @@ -4332,7 +4444,7 @@ static int enable_sysv_units(const char *verb, char **args) { if (!isempty(arg_root)) argv[c++] = q = strappend("--root=", arg_root); - argv[c++] = path_get_file_name(p); + argv[c++] = basename(p); argv[c++] = streq(verb, "enable") ? "on" : streq(verb, "disable") ? "off" : "--level=5"; @@ -4698,9 +4810,9 @@ static int systemctl_help(void) { " -o --output=STRING Change journal output mode (short, short-monotonic,\n" " verbose, export, json, json-pretty, json-sse, cat)\n\n" "Unit Commands:\n" - " list-units List loaded units\n" - " list-sockets List loaded sockets ordered by address\n" - " list-timers List loaded timers ordered by next elapse\n" + " list-units [PATTERN...] List loaded units\n" + " list-sockets [PATTERN...] List loaded sockets ordered by address\n" + " list-timers [PATTERN...] List loaded timers ordered by next elapse\n" " start [NAME...] Start (activate) one or more units\n" " stop [NAME...] Stop (deactivate) one or more units\n" " reload [NAME...] Reload one or more units\n" @@ -4717,6 +4829,7 @@ static int systemctl_help(void) { " status [NAME...|PID...] Show runtime status of one or more units\n" " show [NAME...|JOB...] Show properties of one or more\n" " units/jobs or the manager\n" + " cat [NAME...] Show files and drop-ins of one or more units\n" " set-property [NAME] [ASSIGNMENT...]\n" " Sets one or more properties of a unit\n" " help [NAME...|PID...] Show manual for one or more units\n" @@ -4726,7 +4839,7 @@ static int systemctl_help(void) { " or wanted by this unit or by which this\n" " unit is required or wanted\n\n" "Unit File Commands:\n" - " list-unit-files List installed unit files\n" + " list-unit-files [PATTERN...] List installed unit files\n" " enable [NAME...] Enable one or more unit files\n" " disable [NAME...] Disable one or more unit files\n" " reenable [NAME...] Reenable one or more unit files\n" @@ -4740,7 +4853,7 @@ static int systemctl_help(void) { " get-default Get the name of the default target\n" " set-default NAME Set the default target\n\n" "Job Commands:\n" - " list-jobs List jobs\n" + " list-jobs [PATTERN...] List jobs\n" " cancel [JOB...] Cancel all, one, or more jobs\n\n" "Snapshot Commands:\n" " snapshot [NAME] Create a snapshot\n" @@ -4841,7 +4954,7 @@ static int help_types(void) { const char *t; puts("Available unit types:"); - for(i = 0; i < _UNIT_TYPE_MAX; i++) { + for (i = 0; i < _UNIT_TYPE_MAX; i++) { t = unit_type_to_string(i); if (t) puts(t); @@ -5676,11 +5789,11 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { const int argc; int (* const dispatch)(sd_bus *bus, char **args); } verbs[] = { - { "list-units", LESS, 1, list_units }, - { "list-unit-files", EQUAL, 1, list_unit_files }, - { "list-sockets", LESS, 1, list_sockets }, - { "list-timers", LESS, 1, list_timers }, - { "list-jobs", EQUAL, 1, list_jobs }, + { "list-units", MORE, 0, list_units }, + { "list-unit-files", MORE, 1, list_unit_files }, + { "list-sockets", MORE, 1, list_sockets }, + { "list-timers", MORE, 1, list_timers }, + { "list-jobs", MORE, 1, list_jobs }, { "clear-jobs", EQUAL, 1, daemon_reload }, { "cancel", MORE, 2, cancel_job }, { "start", MORE, 2, start_unit }, @@ -5700,6 +5813,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { { "check", MORE, 2, check_unit_active }, { "is-failed", MORE, 2, check_unit_failed }, { "show", MORE, 1, show }, + { "cat", MORE, 2, cat }, { "status", MORE, 1, show }, { "help", MORE, 2, show }, { "snapshot", LESS, 2, snapshot },