X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=62b5616d8084c35c2aadc85a9f7a66d83d906fab;hp=ef1a0799111856db5169fabb793387edddfd81be;hb=ddca82aca08712a302cfabdbe59f73ee9ed3f73a;hpb=7041efe9600e569da6089c36d00fa3ff58e33178 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ef1a07991..62b5616d8 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -69,7 +69,7 @@ #include "fileio.h" static char **arg_types = NULL; -static char **arg_load_states = NULL; +static char **arg_states = NULL; static char **arg_properties = NULL; static bool arg_all = false; static enum dependency { @@ -93,7 +93,6 @@ static bool arg_quiet = false; static bool arg_full = false; static int arg_force = 0; static bool arg_ask_password = true; -static bool arg_failed = false; static bool arg_runtime = false; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; @@ -176,30 +175,6 @@ static void polkit_agent_open_if_enabled(void) { } #endif -static const char *ansi_highlight(bool b) { - - if (!on_tty()) - return ""; - - return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF; -} - -static const char *ansi_highlight_red(bool b) { - - if (!on_tty()) - return ""; - - return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF; -} - -static const char *ansi_highlight_green(bool b) { - - if (!on_tty()) - return ""; - - return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF; -} - static int translate_bus_error_to_exit_status(int r, const DBusError *error) { assert(error); @@ -301,12 +276,11 @@ static int compare_unit_info(const void *a, const void *b) { static bool output_show_unit(const struct unit_info *u) { const char *dot; - if (arg_failed) - return streq(u->active_state, "failed"); + if (!strv_isempty(arg_states)) + return strv_contains(arg_states, u->load_state) || strv_contains(arg_states, u->sub_state) || strv_contains(arg_states, u->active_state); return (!arg_types || ((dot = strrchr(u->id, '.')) && strv_find(arg_types, dot+1))) && - (!arg_load_states || strv_find(arg_load_states, u->load_state)) && (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0); } @@ -381,15 +355,16 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { n_shown++; - if (streq(u->load_state, "error")) { - on_loaded = on = ansi_highlight_red(true); - off_loaded = off = ansi_highlight_red(false); + if (streq(u->load_state, "error") || + streq(u->load_state, "not-found")) { + on_loaded = on = ansi_highlight_red(); + off_loaded = off = ansi_highlight_off(); } else on_loaded = off_loaded = ""; if (streq(u->active_state, "failed")) { - on_active = on = ansi_highlight_red(true); - off_active = off = ansi_highlight_red(false); + on_active = on = ansi_highlight_red(); + off_active = off = ansi_highlight_off(); } else on_active = off_active = ""; @@ -417,11 +392,11 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { if (job_count) printf("JOB = Pending job for the unit.\n"); puts(""); - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); } else { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } if (arg_all) @@ -435,8 +410,12 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { } } -static int get_unit_list(DBusConnection *bus, DBusMessage **reply, - struct unit_info **unit_infos, unsigned *c) { +static int get_unit_list( + DBusConnection *bus, + DBusMessage **reply, + struct unit_info **unit_infos, + unsigned *c) { + DBusMessageIter iter, sub; size_t size = 0; int r; @@ -498,9 +477,11 @@ static int list_units(DBusConnection *bus, char **args) { return 0; } -static int get_triggered_units(DBusConnection *bus, const char* unit_path, - char*** triggered) -{ +static int get_triggered_units( + DBusConnection *bus, + const char* unit_path, + char*** triggered) { + const char *interface = "org.freedesktop.systemd1.Unit", *triggers_property = "Triggers"; _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; @@ -678,13 +659,13 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { printf("\n"); } - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); if (!arg_no_legend) printf("\n"); } else { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } if (!arg_no_legend) { @@ -833,11 +814,11 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { u->state == UNIT_FILE_MASKED_RUNTIME || u->state == UNIT_FILE_DISABLED || u->state == UNIT_FILE_INVALID) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else if (u->state == UNIT_FILE_ENABLED) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); + on = ansi_highlight_green(); + off = ansi_highlight_off(); } else on = off = ""; @@ -1180,7 +1161,7 @@ static int list_dependencies(DBusConnection *bus, char **args) { static int get_default(DBusConnection *bus, char **args) { char *path = NULL; - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; int r; _cleanup_dbus_error_free_ DBusError error; @@ -1245,8 +1226,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) { assert(n == 0 || jobs); if (n == 0) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); + on = ansi_highlight_green(); + off = ansi_highlight_off(); printf("%sNo jobs running.%s\n", on, off); return; @@ -1282,8 +1263,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) { _cleanup_free_ char *e = NULL; if (streq(j->state, "running")) { - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); } else on = off = ""; @@ -1296,8 +1277,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) { } } - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); if (on_tty()) printf("\n%s%zu jobs listed%s.\n", on, n, off); @@ -1383,36 +1364,6 @@ static int list_jobs(DBusConnection *bus, char **args) { return 0; } -static int load_unit(DBusConnection *bus, char **args) { - char **name; - - assert(args); - - STRV_FOREACH(name, args+1) { - _cleanup_free_ char *n = NULL; - int r; - - n = unit_name_mangle(*name); - if (!n) - return log_oom(); - - r = bus_method_call_with_reply( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "LoadUnit", - NULL, - NULL, - DBUS_TYPE_STRING, &n, - DBUS_TYPE_INVALID); - if (r < 0) - return r; - } - - return 0; -} - static int cancel_job(DBusConnection *bus, char **args) { char **name; @@ -1448,8 +1399,9 @@ static int cancel_job(DBusConnection *bus, char **args) { return 0; } -static bool need_daemon_reload(DBusConnection *bus, const char *unit) { +static int need_daemon_reload(DBusConnection *bus, const char *unit) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_dbus_error_free_ DBusError error; dbus_bool_t b = FALSE; DBusMessageIter iter, sub; const char @@ -1459,6 +1411,8 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { _cleanup_free_ char *n = NULL; int r; + dbus_error_init(&error); + /* We ignore all errors here, since this is used to show a warning only */ n = unit_name_mangle(unit); @@ -1472,7 +1426,7 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { "org.freedesktop.systemd1.Manager", "GetUnit", &reply, - NULL, + &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); if (r < 0) @@ -1493,7 +1447,7 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { "org.freedesktop.DBus.Properties", "Get", &reply, - NULL, + &error, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); @@ -1541,6 +1495,7 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { uint32_t id; const char *path, *result, *unit; + char *r; if (dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &id, @@ -1549,7 +1504,11 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID)) { - free(set_remove(d->set, (char*) path)); + r = set_remove(d->set, (char*) path); + if (!r) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + free(r); if (!isempty(result)) d->result = strdup(result); @@ -1559,7 +1518,7 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -#ifndef LEGACY +#ifndef NOLEGACY dbus_error_free(&error); if (dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &id, @@ -1569,7 +1528,11 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me /* Compatibility with older systemd versions < * 183 during upgrades. This should be dropped * one day. */ - free(set_remove(d->set, (char*) path)); + r = set_remove(d->set, (char*) path); + if (!r) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + free(r); if (*result) d->result = strdup(result); @@ -1913,7 +1876,7 @@ static int start_unit_one( return -EIO; } - if (need_daemon_reload(bus, n)) + if (need_daemon_reload(bus, n) > 0) log_warning("Warning: Unit file of %s changed on disk, 'systemctl %sdaemon-reload' recommended.", n, arg_scope == UNIT_FILE_SYSTEM ? "" : "--user "); @@ -2524,6 +2487,10 @@ typedef struct UnitStatusInfo { usec_t condition_timestamp; bool condition_result; + bool failed_condition_trigger; + bool failed_condition_negate; + const char *failed_condition; + const char *failed_condition_param; /* Socket */ unsigned n_accepted; @@ -2545,7 +2512,8 @@ typedef struct UnitStatusInfo { LIST_HEAD(ExecStatusInfo, exec); } UnitStatusInfo; -static void print_status_info(UnitStatusInfo *i) { +static void print_status_info(UnitStatusInfo *i, + bool *ellipsized) { ExecStatusInfo *p; const char *on, *off, *ss; usec_t timestamp; @@ -2576,8 +2544,8 @@ static void print_status_info(UnitStatusInfo *i) { printf(" Follow: unit currently follows state of %s\n", i->following); if (streq_ptr(i->load_state, "error")) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else on = off = ""; @@ -2627,11 +2595,11 @@ static void print_status_info(UnitStatusInfo *i) { ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state; if (streq_ptr(i->active_state, "failed")) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); + on = ansi_highlight_green(); + off = ansi_highlight_off(); } else on = off = ""; @@ -2666,10 +2634,15 @@ static void print_status_info(UnitStatusInfo *i) { s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp); s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); - if (s1) - printf(" start condition failed at %s; %s\n", s2, s1); - else if (s2) - printf(" start condition failed at %s\n", s2); + printf(" start condition failed at %s%s%s\n", + s2, s1 ? "; " : "", s1 ? s1 : ""); + if (i->failed_condition_trigger) + printf(" none of the trigger conditions were met\n"); + else if (i->failed_condition) + printf(" %s=%s%s was not met\n", + i->failed_condition, + i->failed_condition_negate ? "!" : "", + i->failed_condition_param); } if (i->sysfs_path) @@ -2701,8 +2674,8 @@ static void print_status_info(UnitStatusInfo *i) { good = is_clean_exit_lsb(p->code, p->status, NULL); if (!good) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else on = off = ""; @@ -2779,7 +2752,7 @@ static void print_status_info(UnitStatusInfo *i) { printf(" Status: \"%s\"\n", i->status_text); if (i->control_group && - (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->control_group, false) == 0)) { + (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) { unsigned c; printf(" CGroup: %s\n", i->control_group); @@ -2801,7 +2774,7 @@ static void print_status_info(UnitStatusInfo *i) { if (i->control_pid > 0) extra[k++] = i->control_pid; - show_cgroup_and_extra_by_spec(i->control_group, prefix, + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, flags); } } @@ -2816,13 +2789,14 @@ static void print_status_info(UnitStatusInfo *i) { arg_lines, getuid(), flags, - arg_scope == UNIT_FILE_SYSTEM); + arg_scope == UNIT_FILE_SYSTEM, + ellipsized); } if (i->need_daemon_reload) printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n", - ansi_highlight_red(true), - ansi_highlight_red(false), + ansi_highlight_red(), + ansi_highlight_off(), arg_scope == UNIT_FILE_SYSTEM ? "" : "--user "); } @@ -2910,9 +2884,13 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn i->fragment_path = s; else if (streq(name, "SourcePath")) i->source_path = s; -#ifndef LEGACY - else if (streq(name, "DefaultControlGroup")) - i->control_group = s; +#ifndef NOLEGACY + else if (streq(name, "DefaultControlGroup")) { + const char *e; + e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":"); + if (e) + i->control_group = e; + } #endif else if (streq(name, "ControlGroup")) i->control_group = s; @@ -3024,15 +3002,18 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn ExecStatusInfo *info; int r; - if (!(info = new0(ExecStatusInfo, 1))) + info = new0(ExecStatusInfo, 1); + if (!info) return -ENOMEM; - if (!(info->name = strdup(name))) { + info->name = strdup(name); + if (!info->name) { free(info); return -ENOMEM; } - if ((r = exec_status_info_deserialize(&sub, info)) < 0) { + r = exec_status_info_deserialize(&sub, info); + if (r < 0) { free(info); return r; } @@ -3042,7 +3023,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn dbus_message_iter_next(&sub); } - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) { + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && + streq(name, "Listen")) { DBusMessageIter sub, sub2; dbus_message_iter_recurse(iter, &sub); @@ -3068,7 +3050,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn return 0; - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) { + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && + streq(name, "DropInPaths")) { int r = bus_parse_strv_iter(iter, &i->dropin_paths); if (r < 0) return r; @@ -3091,6 +3074,36 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn dbus_message_iter_next(&sub); } + + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && + streq(name, "Conditions")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *cond, *param; + dbus_bool_t trigger, negate; + dbus_int32_t state; + + dbus_message_iter_recurse(&sub, &sub2); + log_debug("here"); + + if(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &cond, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &trigger, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &negate, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, ¶m, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &state, false) >= 0) { + log_debug("%s %d %d %s %d", cond, trigger, negate, param, state); + if (state < 0 && (!trigger || !i->failed_condition)) { + i->failed_condition = cond; + i->failed_condition_trigger = trigger; + i->failed_condition_negate = negate; + i->failed_condition_param = param; + } + } + + dbus_message_iter_next(&sub); + } } break; @@ -3259,30 +3272,6 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *controller, *attr, *value; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) { - - printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n", - controller, - attr, - value); - } - - dbus_message_iter_next(&sub); - } - - return 0; - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) { DBusMessageIter sub; @@ -3335,6 +3324,24 @@ static int print_property(const char *name, DBusMessageIter *iter) { } return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "BlockIODeviceWeight")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *path; + uint64_t weight; + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &weight, false) >= 0) + printf("%s=%s %" PRIu64 "\n", name, strna(path), weight); + + dbus_message_iter_next(&sub); + } + return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) { DBusMessageIter sub, sub2; @@ -3367,7 +3374,12 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; } -static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { +static int show_one(const char *verb, + DBusConnection *bus, + const char *path, + bool show_properties, + bool *new_line, + bool *ellipsized) { _cleanup_free_ DBusMessage *reply = NULL; const char *interface = ""; int r; @@ -3437,7 +3449,7 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo if (streq(verb, "help")) show_unit_help(&info); else - print_status_info(&info); + print_status_info(&info, ellipsized); } strv_free(info.documentation); @@ -3458,7 +3470,7 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo r = 1; else r = 3; - } + } while ((p = info.exec)) { LIST_REMOVE(ExecStatusInfo, exec, info.exec, p); @@ -3468,7 +3480,11 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo return r; } -static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) { +static int show_one_by_pid(const char *verb, + DBusConnection *bus, + uint32_t pid, + bool *new_line, + bool *ellipsized) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; const char *path = NULL; _cleanup_dbus_error_free_ DBusError error; @@ -3496,11 +3512,15 @@ static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, return -EIO; } - r = show_one(verb, bus, path, false, new_line); + r = show_one(verb, bus, path, false, new_line, ellipsized); return r; } -static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) { +static int show_all(const char* verb, + DBusConnection *bus, + bool show_properties, + bool *new_line, + bool *ellipsized) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; _cleanup_free_ struct unit_info *unit_infos = NULL; unsigned c = 0; @@ -3525,7 +3545,7 @@ static int show_all(const char* verb, DBusConnection *bus, bool show_properties, printf("%s -> '%s'\n", u->id, p); - r = show_one(verb, bus, p, show_properties, new_line); + r = show_one(verb, bus, p, show_properties, new_line, ellipsized); if (r != 0) return r; } @@ -3537,6 +3557,7 @@ static int show(DBusConnection *bus, char **args) { int r, ret = 0; bool show_properties, show_status, new_line = false; char **name; + bool ellipsized = false; assert(bus); assert(args); @@ -3550,48 +3571,51 @@ static int show(DBusConnection *bus, char **args) { /* If no argument is specified inspect the manager itself */ if (show_properties && strv_length(args) <= 1) - return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line); + return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); if (show_status && strv_length(args) <= 1) - return show_all(args[0], bus, false, &new_line); - - STRV_FOREACH(name, args+1) { - uint32_t id; + ret = show_all(args[0], bus, false, &new_line, &ellipsized); + else + STRV_FOREACH(name, args+1) { + uint32_t id; - if (safe_atou32(*name, &id) < 0) { - _cleanup_free_ char *p = NULL, *n = NULL; - /* Interpret as unit name */ + if (safe_atou32(*name, &id) < 0) { + _cleanup_free_ char *p = NULL, *n = NULL; + /* Interpret as unit name */ - n = unit_name_mangle(*name); - if (!n) - return log_oom(); + n = unit_name_mangle(*name); + if (!n) + return log_oom(); - p = unit_dbus_path_from_name(n); - if (!p) - return log_oom(); + p = unit_dbus_path_from_name(n); + if (!p) + return log_oom(); - r = show_one(args[0], bus, p, show_properties, &new_line); - if (r != 0) - ret = r; + 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; + } else if (show_properties) { + _cleanup_free_ char *p = NULL; - /* Interpret as job id */ - if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) - return log_oom(); + /* Interpret as job id */ + if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) + return log_oom(); - r = show_one(args[0], bus, p, show_properties, &new_line); - if (r != 0) - ret = r; + 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); - if (r != 0) - ret = r; + } else { + /* Interpret as PID */ + r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized); + if (r != 0) + ret = r; + } } - } + + if (ellipsized && !arg_quiet) + printf("Hint: Some lines were ellipsized, use -l to show in full.\n"); return ret; } @@ -3633,7 +3657,7 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b)) return log_oom(); - } else if (streq(field, "MemoryLimit") || streq(field, "MemorySoftLimit")) { + } else if (streq(field, "MemoryLimit")) { off_t bytes; uint64_t u; @@ -3688,6 +3712,11 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { rwm = ""; } + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) || !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) || !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &rwm) || @@ -3698,6 +3727,94 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { if (!dbus_message_iter_close_container(&sub, &sub2)) return log_oom(); + } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) { + DBusMessageIter sub2; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) || + !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2)) + return log_oom(); + + if (!isempty(eq)) { + const char *path, *bandwidth; + DBusMessageIter sub3; + uint64_t u; + off_t bytes; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + bandwidth = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = parse_bytes(bandwidth, &bytes); + if (r < 0) { + log_error("Failed to parse byte value %s.", bandwidth); + return -EINVAL; + } + + u = (uint64_t) bytes; + + if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) || + !dbus_message_iter_close_container(&sub2, &sub3)) + return log_oom(); + } + + if (!dbus_message_iter_close_container(&sub, &sub2)) + return log_oom(); + + } else if (streq(field, "BlockIODeviceWeight")) { + DBusMessageIter sub2; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) || + !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2)) + return log_oom(); + + if (!isempty(eq)) { + const char *path, *weight; + DBusMessageIter sub3; + uint64_t u; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + weight = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = safe_atou64(weight, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, weight); + return -EINVAL; + } + if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) || + !dbus_message_iter_close_container(&sub2, &sub3)) + return log_oom(); + } + + if (!dbus_message_iter_close_container(&sub, &sub2)) + return log_oom(); + } else { log_error("Unknown assignment %s.", assignment); return -EINVAL; @@ -3765,40 +3882,6 @@ static int set_property(DBusConnection *bus, char **args) { return 0; } -static int dump(DBusConnection *bus, char **args) { - _cleanup_free_ DBusMessage *reply = NULL; - DBusError error; - int r; - const char *text; - - dbus_error_init(&error); - - pager_open_if_enabled(); - - r = bus_method_call_with_reply( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "Dump", - &reply, - NULL, - DBUS_TYPE_INVALID); - if (r < 0) - return r; - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - dbus_error_free(&error); - return -EIO; - } - - fputs(text, stdout); - return 0; -} - static int snapshot(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusError error; @@ -3820,7 +3903,7 @@ static int snapshot(DBusConnection *bus, char **args) { if (!n) return log_oom(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3949,9 +4032,9 @@ static int daemon_reload(DBusConnection *bus, char **args) { /* There's always a fallback possible for * legacy actions. */ r = -EADDRNOTAVAIL; - else if (r == -ETIMEDOUT && streq(method, "Reexecute")) - /* On reexecution, we expect a disconnect, not - * a reply */ + else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute")) + /* On reexecution, we expect a disconnect, not a + * reply */ r = 0; else if (r < 0) log_error("Failed to issue method call: %s", bus_error_message(&error)); @@ -4529,51 +4612,6 @@ finish: return r; } -static int set_log_level(DBusConnection *bus, char **args) { - _cleanup_dbus_error_free_ DBusError error; - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - DBusMessageIter iter, sub; - const char* property = "LogLevel"; - const char* interface = "org.freedesktop.systemd1.Manager"; - const char* value; - - assert(bus); - assert(args); - - value = args[1]; - dbus_error_init(&error); - - m = dbus_message_new_method_call("org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.DBus.Properties", - "Set"); - if (!m) - return log_oom(); - - dbus_message_iter_init_append(m, &iter); - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub)) - return log_oom(); - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &value)) { - dbus_message_iter_abandon_container(&iter, &sub); - return log_oom(); - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - return log_oom(); - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - return -EIO; - } - - return 0; -} - static int unit_is_enabled(DBusConnection *bus, char **args) { _cleanup_dbus_error_free_ DBusError error; int r; @@ -4671,19 +4709,20 @@ static int systemctl_help(void) { " -h --help Show this help\n" " --version Show package version\n" " -t --type=TYPE List only units of a particular type\n" + " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n" " -p --property=NAME Show only properties by this name\n" " -a --all Show all loaded units/properties, including dead/empty\n" " ones. To list all units installed on the system, use\n" " the 'list-unit-files' command instead.\n" " --reverse Show reverse dependencies with 'list-dependencies'\n" - " --failed Show only failed units\n" " -l --full Don't ellipsize unit names on output\n" " --fail When queueing a new job, fail if conflicting jobs are\n" " pending\n" - " --irreversible Create jobs which cannot be implicitly cancelled\n" - " --show-types When showing sockets, explicitly show their type\n" + " --irreversible When queueing a new job, make sure it cannot be implicitly\n" + " cancelled\n" " --ignore-dependencies\n" " When queueing a new job, ignore all its dependencies\n" + " --show-types When showing sockets, explicitly show their type\n" " -i --ignore-inhibitors\n" " When shutting down or sleeping, ignore inhibitors\n" " --kill-who=WHO Who to send signal to\n" @@ -4703,11 +4742,11 @@ static int systemctl_help(void) { " --system Connect to system manager\n" " --user Connect to user service manager\n" " --global Enable/disable unit files globally\n" + " --runtime Enable unit files only temporarily until next reboot\n" " -f --force When enabling unit files, override existing symlinks\n" " When shutting down, execute action immediately\n" " --root=PATH Enable unit files in the specified root directory\n" - " --runtime Enable unit files only temporarily until next reboot\n" - " -n --lines=INTEGER Journal entries to show\n" + " -n --lines=INTEGER Numer of journal entries to show\n" " -o --output=STRING Change journal output mode (short, short-monotonic,\n" " verbose, export, json, json-pretty, json-sse, cat)\n\n" "Unit Commands:\n" @@ -4734,7 +4773,6 @@ static int systemctl_help(void) { " help [NAME...|PID...] Show manual for one or more units\n" " reset-failed [NAME...] Reset failed state for all, one, or more\n" " units\n" - " load [NAME...] Load one or more units\n" " list-dependencies [NAME] Recursively show units which are required\n" " or wanted by this unit or by which this\n" " unit is required or wanted\n\n" @@ -4745,26 +4783,23 @@ static int systemctl_help(void) { " reenable [NAME...] Reenable one or more unit files\n" " preset [NAME...] Enable/disable one or more unit files\n" " based on preset configuration\n" + " is-enabled [NAME...] Check whether unit files are enabled\n\n" " mask [NAME...] Mask one or more units\n" " unmask [NAME...] Unmask one or more units\n" " link [PATH...] Link one or more units files into\n" " the search path\n" " get-default Get the name of the default target\n" - " set-default NAME Set the default target\n" - " is-enabled [NAME...] Check whether unit files are enabled\n\n" + " set-default NAME Set the default target\n\n" "Job Commands:\n" " list-jobs List jobs\n" " cancel [JOB...] Cancel all, one, or more jobs\n\n" - "Status Commands:\n" - " dump Dump server status\n" "Snapshot Commands:\n" " snapshot [NAME] Create a snapshot\n" " delete [NAME...] Remove one or more snapshots\n\n" "Environment Commands:\n" " show-environment Dump environment\n" " set-environment [NAME=VALUE...] Set one or more environment variables\n" - " unset-environment [NAME...] Unset one or more environment variables\n" - " set-log-level LEVEL Set logging threshold for systemd\n\n" + " unset-environment [NAME...] Unset one or more environment variables\n\n" "Manager Lifecycle Commands:\n" " daemon-reload Reload systemd manager configuration\n" " daemon-reexec Reexecute systemd manager\n\n" @@ -4862,13 +4897,6 @@ static int help_types(void) { puts(t); } - puts("\nAvailable unit load states: "); - for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) { - t = unit_load_state_to_string(i); - if (t) - puts(t); - } - return 0; } @@ -4897,46 +4925,48 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_FAILED, ARG_RUNTIME, ARG_FORCE, - ARG_PLAIN + ARG_PLAIN, + ARG_STATE }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "type", required_argument, NULL, 't' }, - { "property", required_argument, NULL, 'p' }, - { "all", no_argument, NULL, 'a' }, - { "reverse", no_argument, NULL, ARG_REVERSE }, - { "after", no_argument, NULL, ARG_AFTER }, - { "before", no_argument, NULL, ARG_BEFORE }, - { "show-types", no_argument, NULL, ARG_SHOW_TYPES }, - { "failed", no_argument, NULL, ARG_FAILED }, - { "full", no_argument, NULL, 'l' }, - { "fail", no_argument, NULL, ARG_FAIL }, - { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, - { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, - { "ignore-inhibitors", no_argument, NULL, 'i' }, - { "user", no_argument, NULL, ARG_USER }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "global", no_argument, NULL, ARG_GLOBAL }, - { "no-block", no_argument, NULL, ARG_NO_BLOCK }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "no-wall", no_argument, NULL, ARG_NO_WALL }, - { "quiet", no_argument, NULL, 'q' }, - { "root", required_argument, NULL, ARG_ROOT }, - { "force", no_argument, NULL, ARG_FORCE }, - { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, - { "kill-who", required_argument, NULL, ARG_KILL_WHO }, - { "signal", required_argument, NULL, 's' }, - { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, - { "host", required_argument, NULL, 'H' }, - { "privileged",no_argument, NULL, 'P' }, - { "runtime", no_argument, NULL, ARG_RUNTIME }, - { "lines", required_argument, NULL, 'n' }, - { "output", required_argument, NULL, 'o' }, - { "plain", no_argument, NULL, ARG_PLAIN }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "type", required_argument, NULL, 't' }, + { "property", required_argument, NULL, 'p' }, + { "all", no_argument, NULL, 'a' }, + { "reverse", no_argument, NULL, ARG_REVERSE }, + { "after", no_argument, NULL, ARG_AFTER }, + { "before", no_argument, NULL, ARG_BEFORE }, + { "show-types", no_argument, NULL, ARG_SHOW_TYPES }, + { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */ + { "full", no_argument, NULL, 'l' }, + { "fail", no_argument, NULL, ARG_FAIL }, + { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, + { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, + { "ignore-inhibitors", no_argument, NULL, 'i' }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "global", no_argument, NULL, ARG_GLOBAL }, + { "no-block", no_argument, NULL, ARG_NO_BLOCK }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-wall", no_argument, NULL, ARG_NO_WALL }, + { "quiet", no_argument, NULL, 'q' }, + { "root", required_argument, NULL, ARG_ROOT }, + { "force", no_argument, NULL, ARG_FORCE }, + { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, + { "kill-who", required_argument, NULL, ARG_KILL_WHO }, + { "signal", required_argument, NULL, 's' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "host", required_argument, NULL, 'H' }, + { "privileged", no_argument, NULL, 'P' }, + { "runtime", no_argument, NULL, ARG_RUNTIME }, + { "lines", required_argument, NULL, 'n' }, + { "output", required_argument, NULL, 'o' }, + { "plain", no_argument, NULL, ARG_PLAIN }, + { "state", required_argument, NULL, ARG_STATE }, + { NULL, 0, NULL, 0 } }; int c; @@ -4980,8 +5010,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) { continue; } + /* It's much nicer to use --state= for + * load states, but let's support this + * in --types= too for compatibility + * with old versions */ if (unit_load_state_from_string(optarg) >= 0) { - if (strv_push(&arg_load_states, type)) + if (strv_push(&arg_states, type) < 0) return log_oom(); type = NULL; continue; @@ -5013,7 +5047,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { if (!prop) return log_oom(); - if (strv_push(&arg_properties, prop)) { + if (strv_push(&arg_properties, prop) < 0) { free(prop); return log_oom(); } @@ -5097,7 +5131,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_FAILED: - arg_failed = true; + if (strv_extend(&arg_states, "failed") < 0) + return log_oom(); + break; case 'q': @@ -5167,6 +5203,25 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_plain = true; break; + case ARG_STATE: { + char *word, *state; + size_t size; + + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + char *s; + + s = strndup(word, size); + if (!s) + return log_oom(); + + if (strv_push(&arg_states, s) < 0) { + free(s); + return log_oom(); + } + } + break; + } + case '?': return -EINVAL; @@ -5756,7 +5811,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "list-sockets", LESS, 1, list_sockets }, { "list-jobs", EQUAL, 1, list_jobs }, { "clear-jobs", EQUAL, 1, daemon_reload }, - { "load", MORE, 2, load_unit }, { "cancel", MORE, 2, cancel_job }, { "start", MORE, 2, start_unit }, { "stop", MORE, 2, start_unit }, @@ -5777,7 +5831,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "show", MORE, 1, show }, { "status", MORE, 1, show }, { "help", MORE, 2, show }, - { "dump", EQUAL, 1, dump }, { "snapshot", LESS, 2, snapshot }, { "delete", MORE, 2, delete_snapshot }, { "daemon-reload", EQUAL, 1, daemon_reload }, @@ -5809,7 +5862,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "list-dependencies", LESS, 2, list_dependencies }, { "set-default", EQUAL, 2, enable_unit }, { "get-default", LESS, 1, get_default }, - { "set-log-level", EQUAL, 2, set_log_level }, { "set-property", MORE, 3, set_property }, }; @@ -6223,7 +6275,7 @@ finish: dbus_shutdown(); strv_free(arg_types); - strv_free(arg_load_states); + strv_free(arg_states); strv_free(arg_properties); pager_close();