}
}
-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;
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;
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,
return 0;
}
-static int set_cgroup(DBusConnection *bus, char **args) {
- _cleanup_free_ char *n = NULL;
- const char *method, *runtime;
- char **argument;
- int r;
-
- assert(bus);
- assert(args);
-
- method =
- streq(args[0], "set-cgroup") ? "SetUnitControlGroup" :
- streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
- : "UnsetUnitControlGroupAttribute";
-
- runtime = arg_runtime ? "runtime" : "persistent";
-
- n = unit_name_mangle(args[1]);
- if (!n)
- return log_oom();
-
- STRV_FOREACH(argument, args + 2) {
-
- r = bus_method_call_with_reply(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method,
- NULL,
- NULL,
- DBUS_TYPE_STRING, &n,
- DBUS_TYPE_STRING, argument,
- DBUS_TYPE_STRING, &runtime,
- DBUS_TYPE_INVALID);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int set_cgroup_attr(DBusConnection *bus, char **args) {
- _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
- DBusMessageIter iter;
- _cleanup_free_ char *n = NULL;
- const char *runtime;
- int r;
-
- assert(bus);
- assert(args);
-
- dbus_error_init(&error);
-
- runtime = arg_runtime ? "runtime" : "persistent";
-
- 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",
- "SetUnitControlGroupAttribute");
- if (!m)
- return log_oom();
-
- dbus_message_iter_init_append(m, &iter);
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
- !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
- return log_oom();
-
- r = bus_append_strv_iter(&iter, args + 3);
- if (r < 0)
- return log_oom();
-
- 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));
- dbus_error_free(&error);
- return -EIO;
- }
-
- return 0;
-}
-
-static int get_cgroup_attr(DBusConnection *bus, char **args) {
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- _cleanup_free_ char *n = NULL;
- char **argument;
- int r;
-
- assert(bus);
- assert(args);
-
- n = unit_name_mangle(args[1]);
- if (!n)
- return log_oom();
-
- STRV_FOREACH(argument, args + 2) {
- _cleanup_strv_free_ char **list = NULL;
- DBusMessageIter iter;
- char **a;
-
- r = bus_method_call_with_reply(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnitControlGroupAttribute",
- &reply,
- NULL,
- DBUS_TYPE_STRING, &n,
- DBUS_TYPE_STRING, argument,
- DBUS_TYPE_INVALID);
- if (r < 0)
- return r;
-
- if (!dbus_message_iter_init(reply, &iter)) {
- log_error("Failed to initialize iterator.");
- return -EIO;
- }
-
- 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;
-}
-
typedef struct ExecStatusInfo {
char *name;
const char *fragment_path;
const char *source_path;
- const char *default_control_group;
+ const char *control_group;
char **dropin_paths;
pid_t main_pid;
pid_t control_pid;
const char *status_text;
+ const char *pid_file;
bool running:1;
usec_t start_timestamp;
if (i->status_text)
printf(" Status: \"%s\"\n", i->status_text);
- if (i->default_control_group &&
- (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
+ if (i->control_group &&
+ (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
unsigned c;
- printf(" CGroup: %s\n", i->default_control_group);
+ printf(" CGroup: %s\n", i->control_group);
if (arg_transport != TRANSPORT_SSH) {
unsigned k = 0;
if (i->control_pid > 0)
extra[k++] = i->control_pid;
- show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
+ show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix,
c, false, extra, k, flags);
}
}
i->fragment_path = s;
else if (streq(name, "SourcePath"))
i->source_path = s;
- else if (streq(name, "DefaultControlGroup"))
- i->default_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;
else if (streq(name, "StatusText"))
i->status_text = s;
+ else if (streq(name, "PIDFile"))
+ i->pid_file = s;
else if (streq(name, "SysFSPath"))
i->sysfs_path = s;
else if (streq(name, "Where"))
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;
}
return 0;
+
+ } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "DeviceAllow")) {
+ DBusMessageIter sub, sub2;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+ const char *path, *rwm;
+
+ 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_STRING, &rwm, false) >= 0)
+ printf("%s=%s %s\n", name, strna(path), strna(rwm));
+
+ 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;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+ const char *path;
+ uint64_t bandwidth;
+
+ 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, &bandwidth, false) >= 0)
+ printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
+
+ dbus_message_iter_next(&sub);
+ }
+ return 0;
}
+
break;
}
if (!streq_ptr(info.active_state, "active") &&
!streq_ptr(info.active_state, "reloading") &&
- streq(verb, "status"))
+ streq(verb, "status")) {
/* According to LSB: "program not running" */
- r = 3;
+ /* 0: program is running or service is OK
+ * 1: program is dead and /var/run pid file exists
+ * 2: program is dead and /var/lock lock file exists
+ * 3: program is not running
+ * 4: program or service status is unknown
+ */
+ if (info.pid_file && access(info.pid_file, F_OK) == 0)
+ r = 1;
+ else
+ r = 3;
+ }
while ((p = info.exec)) {
LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
return ret;
}
+static int append_assignment(DBusMessageIter *iter, const char *assignment) {
+ const char *eq;
+ char *field;
+ DBusMessageIter sub;
+ int r;
+
+ assert(iter);
+ assert(assignment);
+
+ eq = strchr(assignment, '=');
+ if (!eq) {
+ log_error("Not an assignment: %s", assignment);
+ return -EINVAL;
+ }
+
+ field = strndupa(assignment, eq - assignment);
+ eq ++;
+
+ if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field))
+ return log_oom();
+
+ if (streq(field, "CPUAccounting") ||
+ streq(field, "MemoryAccounting") ||
+ streq(field, "BlockIOAccounting")) {
+ dbus_bool_t b;
+
+ r = parse_boolean(eq);
+ if (r < 0) {
+ log_error("Failed to parse boolean assignment %s.", assignment);
+ return -EINVAL;
+ }
+
+ b = r;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "b", &sub) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
+ return log_oom();
+
+ } else if (streq(field, "MemoryLimit") || streq(field, "MemorySoftLimit")) {
+ off_t bytes;
+ uint64_t u;
+
+ r = parse_bytes(eq, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse bytes specification %s", assignment);
+ return -EINVAL;
+ }
+
+ u = bytes;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
+ return log_oom();
+
+ } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
+ uint64_t u;
+
+ r = safe_atou64(eq, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
+ !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;
+ }
+
+ if (!dbus_message_iter_close_container(iter, &sub))
+ return log_oom();
+
+ return 0;
+}
+
+static int set_property(DBusConnection *bus, char **args) {
+
+ _cleanup_free_ DBusMessage *m = NULL, *reply = NULL;
+ DBusMessageIter iter, sub;
+ dbus_bool_t runtime;
+ DBusError error;
+ char **i;
+ int r;
+
+ dbus_error_init(&error);
+
+ m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetUnitProperties");
+ if (!m)
+ return log_oom();
+
+ dbus_message_iter_init_append(m, &iter);
+
+ runtime = arg_runtime;
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[1]) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &runtime) ||
+ !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
+ return log_oom();
+
+ STRV_FOREACH(i, args + 2) {
+ DBusMessageIter sub2;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ return log_oom();
+
+ r = append_assignment(&sub2, *i);
+ if (r < 0)
+ return r;
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ 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));
+ dbus_error_free(&error);
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int dump(DBusConnection *bus, char **args) {
_cleanup_free_ DBusMessage *reply = NULL;
DBusError error;
if (!n)
return log_oom();
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
" 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"
+ " 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"
" reset-failed [NAME...] Reset failed state for all, one, or more\n"
" units\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 or by which this\n"
{ "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
{ "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
{ "isolate", EQUAL, 2, start_unit },
- { "set-cgroup", MORE, 3, set_cgroup },
- { "unset-cgroup", MORE, 3, set_cgroup },
- { "get-cgroup-attr", MORE, 3, get_cgroup_attr },
- { "set-cgroup-attr", MORE, 4, set_cgroup_attr },
- { "unset-cgroup-attr", MORE, 3, set_cgroup },
{ "kill", MORE, 2, kill_unit },
{ "is-active", MORE, 2, check_unit_active },
{ "check", MORE, 2, check_unit_active },
{ "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 },
};
int left;