ACTION_CANCEL_SHUTDOWN,
_ACTION_MAX
} arg_action = ACTION_SYSTEMCTL;
-static enum dot {
- DOT_ALL,
- DOT_ORDER,
- DOT_REQUIRE
-} arg_dot = DOT_ALL;
static enum transport {
TRANSPORT_NORMAL,
TRANSPORT_SSH,
return false;
}
-struct unit_info {
- const char *id;
- const char *description;
- const char *load_state;
- const char *active_state;
- const char *sub_state;
- const char *following;
- const char *unit_path;
- uint32_t job_id;
- const char *job_type;
- const char *job_path;
-};
-
static int compare_unit_info(const void *a, const void *b) {
const char *d1, *d2;
const struct unit_info *u = a, *v = b;
static int list_units(DBusConnection *bus, char **args) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
_cleanup_free_ struct unit_info *unit_infos = NULL;
- DBusMessageIter iter, sub, sub2;
+ DBusMessageIter iter, sub;
unsigned c = 0, n_units = 0;
int r;
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
struct unit_info *u;
- assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
-
if (c >= n_units) {
struct unit_info *w;
u = unit_infos + c;
- dbus_message_iter_recurse(&sub, &sub2);
-
- if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
- log_error("Failed to parse reply.");
- return -EIO;
- }
+ bus_parse_unit_info(&sub, u);
dbus_message_iter_next(&sub);
c++;
}
finish:
if (r < 0)
- strv_freep(&ret);
- *deps = ret;
+ strv_free(ret);
+ else
+ *deps = ret;
return r;
}
return list_dependencies_one(bus, u, 0, NULL, 0);
}
-static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
-
- static const char * const colors[] = {
- "Requires", "[color=\"black\"]",
- "RequiresOverridable", "[color=\"black\"]",
- "Requisite", "[color=\"darkblue\"]",
- "RequisiteOverridable", "[color=\"darkblue\"]",
- "Wants", "[color=\"grey66\"]",
- "Conflicts", "[color=\"red\"]",
- "ConflictedBy", "[color=\"red\"]",
- "After", "[color=\"green\"]"
- };
-
- const char *c = NULL;
- unsigned i;
-
- assert(name);
- assert(prop);
- assert(iter);
-
- for (i = 0; i < ELEMENTSOF(colors); i += 2)
- if (streq(colors[i], prop)) {
- c = colors[i+1];
- break;
- }
-
- if (!c)
- return 0;
-
- if (arg_dot != DOT_ALL)
- if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
- return 0;
-
- switch (dbus_message_iter_get_arg_type(iter)) {
-
- case DBUS_TYPE_ARRAY:
-
- if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
- DBusMessageIter sub;
-
- dbus_message_iter_recurse(iter, &sub);
-
- while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- const char *s;
-
- assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
- dbus_message_iter_get_basic(&sub, &s);
- printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
-
- dbus_message_iter_next(&sub);
- }
-
- return 0;
- }
- }
-
- return 0;
-}
-
-static int dot_one(DBusConnection *bus, const char *name, const char *path) {
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- const char *interface = "org.freedesktop.systemd1.Unit";
- int r;
- DBusMessageIter iter, sub, sub2, sub3;
-
- assert(bus);
- assert(path);
-
- r = bus_method_call_with_reply(
- bus,
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.DBus.Properties",
- "GetAll",
- &reply,
- NULL,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_INVALID);
- if (r < 0)
- return r;
-
- if (!dbus_message_iter_init(reply, &iter) ||
- dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
- log_error("Failed to parse reply.");
- return -EIO;
- }
-
- dbus_message_iter_recurse(&iter, &sub);
-
- while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- const char *prop;
-
- assert(dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY);
- dbus_message_iter_recurse(&sub, &sub2);
-
- if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0 ||
- dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
- log_error("Failed to parse reply.");
- return -EIO;
- }
-
- dbus_message_iter_recurse(&sub2, &sub3);
- r = dot_one_property(name, prop, &sub3);
- if (r < 0)
- return r;
-
- dbus_message_iter_next(&sub);
- }
-
- return 0;
-}
-
-static int dot(DBusConnection *bus, char **args) {
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- DBusMessageIter iter, sub, sub2;
- int r;
-
- r = bus_method_call_with_reply(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits",
- &reply,
- NULL,
- DBUS_TYPE_INVALID);
- if (r < 0)
- return r;
-
- if (!dbus_message_iter_init(reply, &iter) ||
- dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
- log_error("Failed to parse reply.");
- return -EIO;
- }
-
- printf("digraph systemd {\n");
-
- dbus_message_iter_recurse(&iter, &sub);
- while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
-
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
- log_error("Failed to parse reply.");
- return -EIO;
- }
-
- dbus_message_iter_recurse(&sub, &sub2);
-
- if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
- log_error("Failed to parse reply.");
- return -EIO;
- }
-
- r = dot_one(bus, id, unit_path);
- if (r < 0)
- return r;
-
- /* printf("\t\"%s\";\n", id); */
- dbus_message_iter_next(&sub);
- }
-
- printf("}\n");
-
- log_info(" Color legend: black = Requires\n"
- " dark blue = Requisite\n"
- " dark grey = Wants\n"
- " red = Conflicts\n"
- " green = After\n");
-
- if (on_tty())
- log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
- "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
-
- return 0;
-}
-
static int list_jobs(DBusConnection *bus, char **args) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusMessageIter iter, sub, sub2;
DBusMessageIter iter;
int r;
_cleanup_free_ char *n = NULL;
+ const char *runtime;
assert(bus);
assert(args);
if (r < 0)
return log_oom();
+ runtime = arg_runtime ? "runtime" : "persistent";
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
+ 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));
DBusMessageIter iter, sub, sub2;
char **x, **y;
_cleanup_free_ char *n = NULL;
+ const char *runtime;
assert(bus);
assert(args);
return log_oom();
}
- if (!dbus_message_iter_close_container(&iter, &sub))
- return -ENOMEM;
+ runtime = arg_runtime ? "runtime" : "persistent";
+ if (!dbus_message_iter_close_container(&iter, &sub) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
+ 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));
+ dbus_error_free(&error);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int get_cgroup_attr(DBusConnection *bus, char **args) {
+ _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+ DBusError error;
+ DBusMessageIter iter;
+ int r;
+ _cleanup_free_ char *n = NULL;
+ _cleanup_strv_free_ char **list = NULL;
+ char **a;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ n = unit_name_mangle(args[1]);
+ if (!n)
+ return log_oom();
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnitControlGroupAttributes");
+ if (!m)
+ return log_oom();
+
+ dbus_message_iter_init_append(m, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
+ return log_oom();
+
+ r = bus_append_strv_iter(&iter, args + 2);
+ if (r < 0)
+ return log_oom();
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
if (!reply) {
return -EIO;
}
+ dbus_message_iter_init(reply, &iter);
+ r = bus_parse_strv_iter(&iter, &list);
+ if (r < 0) {
+ log_error("Failed to parse value list.");
+ return r;
+ }
+
+ STRV_FOREACH(a, list) {
+ if (endswith(*a, "\n"))
+ fputs(*a, stdout);
+ else
+ puts(*a);
+ }
+
return 0;
}
if (i->id && arg_transport != TRANSPORT_SSH) {
printf("\n");
- show_journal_by_unit(stdout,
- i->id,
- arg_output,
- 0,
- i->inactive_exit_timestamp_monotonic,
- arg_lines,
- flags);
+ if(arg_scope == UNIT_FILE_SYSTEM)
+ show_journal_by_unit(stdout,
+ i->id,
+ arg_output,
+ 0,
+ i->inactive_exit_timestamp_monotonic,
+ arg_lines,
+ flags);
+ else
+ show_journal_by_user_unit(stdout,
+ i->id,
+ arg_output,
+ 0,
+ i->inactive_exit_timestamp_monotonic,
+ arg_lines,
+ getuid(),
+ flags);
}
if (i->need_daemon_reload)
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("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
+ printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
controller,
attr,
value);
" --no-pager Do not pipe output into a pager\n"
" --no-ask-password\n"
" Do not ask for system passwords\n"
- " --order When generating graph for dot, show only order\n"
- " --require When generating graph for dot, show only requirement\n"
" --system Connect to system manager\n"
" --user Connect to user service manager\n"
" --global Enable/disable unit files globally\n"
" 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"
- " set-cgroup [NAME] [CGROUP...] Add unit to a control group\n"
- " unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
+ " get-cgroup-attr [NAME] [ATTR] ...\n"
+ " Get control group attrubute\n"
" set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
" Set control group attribute\n"
" unset-cgroup-attr [NAME] [ATTR...]\n"
" Unset control group attribute\n"
+ " set-cgroup [NAME] [CGROUP...] Add unit to a control group\n"
+ " unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
" load [NAME...] Load one or more units\n"
" list-dependencies [NAME] Recursively show units which are required\n"
" or wanted by this unit\n\n"
" cancel [JOB...] Cancel all, one, or more jobs\n\n"
"Status Commands:\n"
" dump Dump server status\n"
- " dot Dump dependency graph for dot(1)\n\n"
"Snapshot Commands:\n"
" snapshot [NAME] Create a snapshot\n"
" delete [NAME...] Remove one or more snapshots\n\n"
ARG_NO_LEGEND,
ARG_NO_PAGER,
ARG_NO_WALL,
- ARG_ORDER,
- ARG_REQUIRE,
ARG_ROOT,
ARG_FULL,
ARG_NO_RELOAD,
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{ "quiet", no_argument, NULL, 'q' },
- { "order", no_argument, NULL, ARG_ORDER },
- { "require", no_argument, NULL, ARG_REQUIRE },
{ "root", required_argument, NULL, ARG_ROOT },
{ "force", no_argument, NULL, ARG_FORCE },
{ "no-reload", no_argument, NULL, ARG_NO_RELOAD },
arg_no_wall = true;
break;
- case ARG_ORDER:
- arg_dot = DOT_ORDER;
- break;
-
- case ARG_REQUIRE:
- arg_dot = DOT_REQUIRE;
- break;
-
case ARG_ROOT:
arg_root = optarg;
break;
{ "isolate", EQUAL, 2, start_unit },
{ "set-cgroup", MORE, 2, set_cgroup },
{ "unset-cgroup", MORE, 2, set_cgroup },
+ { "get-cgroup-attr", MORE, 2, get_cgroup_attr },
{ "set-cgroup-attr", MORE, 2, set_cgroup_attr },
{ "unset-cgroup-attr", MORE, 2, set_cgroup },
{ "kill", MORE, 2, kill_unit },
{ "status", MORE, 2, show },
{ "help", MORE, 2, show },
{ "dump", EQUAL, 1, dump },
- { "dot", EQUAL, 1, dot },
{ "snapshot", LESS, 2, snapshot },
{ "delete", MORE, 2, delete_snapshot },
{ "daemon-reload", EQUAL, 1, daemon_reload },