X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=9f47b2cf7cebf30b13c948cce41a52d58b6fb67e;hb=d07f7b9ef2835c290d6beadebd17d15308608eea;hp=5048b529e14b6dcae8ae91cf73b0f07a5da157df;hpb=b42defe3b8ed3947d85db654a6cdb1b9999f394d;p=elogind.git diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 5048b529e..9f47b2cf7 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; @@ -301,12 +300,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,7 +379,8 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { n_shown++; - if (streq(u->load_state, "error")) { + if (streq(u->load_state, "error") || + streq(u->load_state, "not-found")) { on_loaded = on = ansi_highlight_red(true); off_loaded = off = ansi_highlight_red(false); } else @@ -435,8 +434,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 +501,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; @@ -1180,7 +1185,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; @@ -1448,8 +1453,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 +1465,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 +1480,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 +1501,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); @@ -1559,7 +1567,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, @@ -1913,7 +1921,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 +2532,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; @@ -2666,10 +2678,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) @@ -2779,7 +2796,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 +2818,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); } } @@ -2910,9 +2927,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 +3045,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 +3066,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 +3093,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 +3117,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 +3315,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; @@ -3458,7 +3490,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); @@ -3661,6 +3693,43 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u)) return log_oom(); + } else if (streq(field, "DevicePolicy")) { + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &sub) || + !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &eq)) + return log_oom(); + + } else if (streq(field, "DeviceAllow")) { + DBusMessageIter sub2; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(ss)", &sub) || + !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(ss)", &sub2)) + return log_oom(); + + if (!isempty(eq)) { + const char *path, *rwm; + DBusMessageIter sub3; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + rwm = e+1; + } else { + path = eq; + rwm = ""; + } + + 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) || + !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; @@ -3783,7 +3852,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", @@ -3912,9 +3981,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)); @@ -4634,12 +4703,12 @@ 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 Show 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" @@ -4719,7 +4788,7 @@ static int systemctl_help(void) { " list-jobs List jobs\n" " cancel [JOB...] Cancel all, one, or more jobs\n\n" "Status Commands:\n" - " dump Dump server status\n" + " dump Dump server status\n\n" "Snapshot Commands:\n" " snapshot [NAME] Create a snapshot\n" " delete [NAME...] Remove one or more snapshots\n\n" @@ -4825,13 +4894,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; } @@ -4860,7 +4922,8 @@ 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[] = { @@ -4899,6 +4962,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "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 } }; @@ -4943,8 +5007,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; @@ -4976,7 +5044,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(); } @@ -5060,7 +5128,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': @@ -5130,6 +5200,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; @@ -6186,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();