#include <systemd/sd-daemon.h>
#include <systemd/sd-shutdown.h>
+#include <systemd/sd-login.h>
#include "log.h"
#include "util.h"
#include "logs-show.h"
#include "path-util.h"
#include "socket-util.h"
+#include "fileio.h"
static const char *arg_type = NULL;
static const char *arg_load_state = NULL;
static bool arg_no_wtmp = false;
static bool arg_no_wall = false;
static bool arg_no_reload = false;
+static bool arg_ignore_inhibitors = false;
static bool arg_dry = false;
static bool arg_quiet = false;
static bool arg_full = false;
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;
if (arg_wall) {
- char *p;
+ _cleanup_free_ char *p;
p = strv_join(arg_wall, " ");
if (!p) {
- log_error("Failed to join strings.");
+ log_oom();
return;
}
if (*p) {
utmp_wall(p, NULL);
- free(p);
return;
}
-
- free(p);
}
if (!table[a])
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;
if (d1 && d2) {
int r;
- if ((r = strcasecmp(d1, d2)) != 0)
+ r = strcasecmp(d1, d2);
+ if (r != 0)
return r;
}
id_len = max_id_len;
for (u = unit_infos; u < unit_infos + c; u++) {
- char *e;
+ char _cleanup_free_ *e = NULL;
const char *on_loaded, *off_loaded;
const char *on_active, *off_active;
printf("%.*s\n", desc_len, u->description);
else
printf("%s\n", u->description);
-
- free(e);
}
if (!arg_no_legend) {
}
}
-static int list_units(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
+static int get_unit_list(DBusConnection *bus, DBusMessage **reply,
+ struct unit_info **unit_infos, unsigned *c) {
+ DBusMessageIter iter, sub;
+ unsigned n_units = 0;
int r;
- DBusMessageIter iter, sub, sub2;
- unsigned c = 0, n_units = 0;
- struct unit_info *unit_infos = NULL;
- pager_open_if_enabled();
+ assert(bus);
+ assert(unit_infos);
+ assert(c);
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"ListUnits",
- &reply,
+ reply,
NULL,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
- if (!dbus_message_iter_init(reply, &iter) ||
+ 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.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
struct unit_info *u;
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
-
- if (c >= n_units) {
+ if (*c >= n_units) {
struct unit_info *w;
- n_units = MAX(2*c, 16);
- w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
-
- if (!w) {
- log_error("Failed to allocate unit array.");
- r = -ENOMEM;
- goto finish;
- }
+ n_units = MAX(2 * *c, 16);
+ w = realloc(*unit_infos, sizeof(struct unit_info) * n_units);
+ if (!w)
+ return log_oom();
- unit_infos = w;
+ *unit_infos = w;
}
- u = unit_infos+c;
-
- dbus_message_iter_recurse(&sub, &sub2);
+ u = *unit_infos + *c;
- 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.");
- r = -EIO;
- goto finish;
- }
+ bus_parse_unit_info(&sub, u);
dbus_message_iter_next(&sub);
- c++;
+ (*c)++;
}
- if (c > 0) {
- qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
- output_units_list(unit_infos, c);
- }
+ if (*c > 0)
+ qsort(*unit_infos, *c, sizeof(struct unit_info), compare_unit_info);
-finish:
- if (reply)
- dbus_message_unref(reply);
+ return 0;
+}
+
+static int list_units(DBusConnection *bus, char **args) {
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ struct unit_info *unit_infos = NULL;
+ unsigned c = 0;
+ int r;
+
+ pager_open_if_enabled();
- free(unit_infos);
+ r = get_unit_list(bus, &reply, &unit_infos, &c);
+ if (r < 0)
+ return r;
- return r;
+ if (c > 0)
+ output_units_list(unit_infos, c);
+
+ return 0;
}
static int compare_unit_file_list(const void *a, const void *b) {
printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
for (u = units; u < units + c; u++) {
- char *e;
+ char _cleanup_free_ *e = NULL;
const char *on, *off;
const char *id;
printf("%-*s %s%-*s%s\n",
id_cols, e ? e : id,
on, state_cols, unit_file_state_to_string(u->state), off);
-
- free(e);
}
if (!arg_no_legend)
}
static int list_unit_files(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
- int r;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ UnitFileList *units = NULL;
DBusMessageIter iter, sub, sub2;
unsigned c = 0, n_units = 0;
- UnitFileList *units = NULL;
+ int r;
pager_open_if_enabled();
hashmap_free(h);
} else {
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
&reply,
NULL,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ 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.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&iter, &sub);
UnitFileList *u;
const char *state;
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
+ assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
if (c >= n_units) {
UnitFileList *w;
n_units = MAX(2*c, 16);
w = realloc(units, sizeof(struct UnitFileList) * n_units);
-
- if (!w) {
- log_error("Failed to allocate unit array.");
- r = -ENOMEM;
- goto finish;
- }
+ if (!w)
+ return log_oom();
units = w;
}
- u = units+c;
+ u = units + c;
dbus_message_iter_recurse(&sub, &sub2);
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
u->state = unit_file_state_from_string(state);
output_unit_file_list(units, c);
}
- r = 0;
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- free(units);
-
- return r;
+ return 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;
+static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
+ int i;
+ _cleanup_free_ char *n = NULL;
+ size_t len = 0;
+ size_t max_len = MAX(columns(),20);
+
+ for (i = level - 1; i >= 0; i--) {
+ len += 2;
+ if(len > max_len - 3 && !arg_full) {
+ printf("%s...\n",max_len % 2 ? "" : " ");
+ return 0;
}
-
- if (!c)
+ printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
+ }
+ len += 2;
+ if(len > max_len - 3 && !arg_full) {
+ printf("%s...\n",max_len % 2 ? "" : " ");
return 0;
+ }
+ printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
- if (arg_dot != DOT_ALL)
- if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
- return 0;
+ if(arg_full){
+ printf("%s\n", name);
+ return 0;
+ }
- switch (dbus_message_iter_get_arg_type(iter)) {
+ n = ellipsize(name, max_len-len, 100);
+ if(!n)
+ return log_oom();
- case DBUS_TYPE_ARRAY:
+ printf("%s\n", n);
+ return 0;
+}
- if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
- DBusMessageIter sub;
+static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
+ static const char dependencies[] =
+ "Requires\0"
+ "RequiresOverridable\0"
+ "Requisite\0"
+ "RequisiteOverridable\0"
+ "Wants\0";
- dbus_message_iter_recurse(iter, &sub);
+ _cleanup_free_ char *path;
+ const char *interface = "org.freedesktop.systemd1.Unit";
- while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- const char *s;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ DBusMessageIter iter, sub, sub2, sub3;
- 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);
+ int r = 0;
+ char **ret = NULL;
- dbus_message_iter_next(&sub);
- }
+ assert(bus);
+ assert(name);
+ assert(deps);
- return 0;
- }
+ path = unit_dbus_path_from_name(name);
+ if (path == NULL) {
+ r = -EINVAL;
+ goto finish;
}
- return 0;
-}
-
-static int dot_one(DBusConnection *bus, const char *name, const char *path) {
- DBusMessage *reply = NULL;
- const char *interface = "org.freedesktop.systemd1.Unit";
- int r;
- DBusMessageIter iter, sub, sub2, sub3;
-
- 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)
+ 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)
goto finish;
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) {
+ 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.");
r = -EIO;
goto finish;
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
const char *prop;
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
-
+ 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) {
goto finish;
}
- if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
+ if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
r = -EIO;
goto finish;
}
dbus_message_iter_recurse(&sub2, &sub3);
+ dbus_message_iter_next(&sub);
- if (dot_one_property(name, prop, &sub3)) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
+ if (!nulstr_contains(dependencies, prop))
+ continue;
- dbus_message_iter_next(&sub);
- }
+ if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
+ if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
+ DBusMessageIter sub4;
+ dbus_message_iter_recurse(&sub3, &sub4);
-finish:
- if (reply)
- dbus_message_unref(reply);
+ while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
+ const char *s;
+
+ assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic(&sub4, &s);
+
+ r = strv_extend(&ret, s);
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
+ dbus_message_iter_next(&sub4);
+ }
+ }
+ }
+ }
+finish:
+ if (r < 0)
+ strv_free(ret);
+ else
+ *deps = ret;
return r;
}
-static int dot(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
- int r;
- DBusMessageIter iter, sub, sub2;
+static int list_dependencies_compare(const void *_a, const void *_b) {
+ const char **a = (const char**) _a, **b = (const char**) _b;
+ if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
+ return 1;
+ if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
+ return -1;
+ return strcasecmp(*a, *b);
+}
- 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)
- goto finish;
+static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char **units, unsigned int branches) {
+ char _cleanup_strv_free_ **deps = NULL, **u;
+ char **c;
+ int r = 0;
- 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.");
- r = -EIO;
- goto finish;
- }
+ u = strv_append(units, name);
+ if (!u)
+ return log_oom();
- printf("digraph systemd {\n");
+ r = list_dependencies_get_dependencies(bus, name, &deps);
+ if (r < 0)
+ return r;
- 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;
+ qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ STRV_FOREACH(c, deps) {
+ if (strv_contains(u, *c)) {
+ r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
+ if (r < 0)
+ return r;
+ continue;
}
- dbus_message_iter_recurse(&sub, &sub2);
+ r = list_dependencies_print(*c, level, branches, c[1] == NULL);
+ if (r < 0)
+ return r;
- 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.");
- r = -EIO;
- goto finish;
+ 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)
+ return r;
}
-
- if ((r = dot_one(bus, id, unit_path)) < 0)
- goto finish;
-
- /* printf("\t\"%s\";\n", id); */
- dbus_message_iter_next(&sub);
}
- printf("}\n");
+ return 0;
+}
- log_info(" Color legend: black = Requires\n"
- " dark blue = Requisite\n"
- " dark grey = Wants\n"
- " red = Conflicts\n"
- " green = After\n");
+static int list_dependencies(DBusConnection *bus, char **args) {
+ _cleanup_free_ char *unit = NULL;
+ const char *u;
- 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");
+ assert(bus);
- r = 0;
+ if (args[1]) {
+ unit = unit_name_mangle(args[1]);
+ if (!unit)
+ return log_oom();
+ u = unit;
+ } else
+ u = SPECIAL_DEFAULT_TARGET;
-finish:
- if (reply)
- dbus_message_unref(reply);
+ pager_open_if_enabled();
- return r;
+ puts(u);
+
+ return list_dependencies_one(bus, u, 0, NULL, 0);
}
static int list_jobs(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
- int r;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusMessageIter iter, sub, sub2;
unsigned k = 0;
+ int r;
pager_open_if_enabled();
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
&reply,
NULL,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ 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.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
const char *name, *type, *state, *job_path, *unit_path;
uint32_t id;
- char *e;
+ char _cleanup_free_ *e = NULL;
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&sub, &sub2);
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
e = arg_full ? NULL : ellipsize(name, 25, 33);
printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
- free(e);
k++;
if (on_tty())
printf("\n%u jobs listed.\n", k);
- r = 0;
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- return r;
+ return 0;
}
static int load_unit(DBusConnection *bus, char **args) {
- int r = 0;
- char **name, *n;
+ char **name;
assert(args);
STRV_FOREACH(name, args+1) {
+ _cleanup_free_ char *n = NULL;
+ int r;
+
n = unit_name_mangle(*name);
- r = bus_method_call_with_reply (
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"LoadUnit",
NULL,
NULL,
- DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_INVALID);
- free(n);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
}
-finish:
- return r;
+ return 0;
}
static int cancel_job(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
- int r = 0;
char **name;
assert(args);
return daemon_reload(bus, args);
STRV_FOREACH(name, args+1) {
- unsigned id;
- const char *path;
+ uint32_t id;
+ int r;
- r = safe_atou(*name, &id);
+ r = safe_atou32(*name, &id);
if (r < 0) {
log_error("Failed to parse job id: %s", strerror(-r));
- goto finish;
+ return r;
}
- assert_cc(sizeof(uint32_t) == sizeof(id));
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "GetJob",
- &reply,
- NULL,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_INVALID);
- if (r)
- goto finish;
-
- if (!dbus_message_get_args(reply, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse reply");
- dbus_message_unref(reply);
- r = -EIO;
- goto finish;
- }
- dbus_message_unref(reply);
-
- r = bus_method_call_with_reply (
- bus,
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.systemd1.Job",
- "Cancel",
+ "CancelJob",
NULL,
NULL,
+ DBUS_TYPE_UINT32, &id,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
}
-finish:
- return r;
+ return 0;
}
static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
- DBusMessage *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
dbus_bool_t b = FALSE;
DBusMessageIter iter, sub;
const char
*interface = "org.freedesktop.systemd1.Unit",
*property = "NeedDaemonReload",
*path;
- char *n;
+ _cleanup_free_ char *n = NULL;
int r;
/* We ignore all errors here, since this is used to show a warning only */
n = unit_name_mangle(unit);
- r = bus_method_call_with_reply (
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"GetUnit",
&reply,
NULL,
- DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_INVALID);
- free(n);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
if (!dbus_message_get_args(reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID))
- goto finish;
+ return -EIO;
dbus_message_unref(reply);
- r = bus_method_call_with_reply (
+ reply = NULL;
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
path,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &property,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- goto finish;
+ return -EIO;
dbus_message_iter_recurse(&iter, &sub);
-
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
- goto finish;
+ return -EIO;
dbus_message_iter_get_basic(&sub, &b);
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
return b;
}
} WaitData;
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
- DBusError error;
+ DBusError _cleanup_dbus_error_free_ error;
WaitData *d = data;
+ dbus_error_init(&error);
+
assert(connection);
assert(message);
assert(d);
- dbus_error_init(&error);
-
log_debug("Got D-Bus request: %s.%s() on %s",
dbus_message_get_interface(message),
dbus_message_get_member(message),
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
const char *path, *result, *unit;
- dbus_bool_t success = true;
if (dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_STRING, &unit,
DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID)) {
- char *p;
- p = set_remove(d->set, (char*) path);
- free(p);
+ free(set_remove(d->set, (char*) path));
if (!isempty(result))
d->result = strdup(result);
if (!isempty(unit))
d->name = strdup(unit);
- goto finish;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#ifndef LEGACY
dbus_error_free(&error);
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID)) {
- char *p;
-
/* Compatibility with older systemd versions <
* 183 during upgrades. This should be dropped
* one day. */
- p = set_remove(d->set, (char*) path);
- free(p);
+ free(set_remove(d->set, (char*) path));
if (*result)
d->result = strdup(result);
- goto finish;
- }
-
- dbus_error_free(&error);
- if (dbus_message_get_args(message, &error,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_BOOLEAN, &success,
- DBUS_TYPE_INVALID)) {
- char *p;
-
- /* Compatibility with older systemd versions <
- * 19 during upgrades. This should be dropped
- * one day */
-
- p = set_remove(d->set, (char*) path);
- free(p);
-
- if (!success)
- d->result = strdup("failed");
-
- goto finish;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif
log_error("Failed to parse message: %s", bus_error_message(&error));
}
-finish:
- dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
return r;
}
-static int check_one_unit(DBusConnection *bus, char *name, char **check_states, bool quiet) {
- DBusMessage *reply = NULL;
+static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ char *n = NULL;
DBusMessageIter iter, sub;
const char
*interface = "org.freedesktop.systemd1.Unit",
*property = "ActiveState";
- const char *path = NULL;
- const char *state;
+ const char *state, *path;
+ DBusError error;
int r;
- char *n;
assert(name);
+ dbus_error_init(&error);
+
n = unit_name_mangle(name);
+ if (!n)
+ return log_oom();
+
r = bus_method_call_with_reply (
bus,
"org.freedesktop.systemd1",
"org.freedesktop.systemd1.Manager",
"GetUnit",
&reply,
- NULL,
- DBUS_TYPE_STRING, n ? &n : &name,
+ &error,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_INVALID);
- free(n);
- if (r) {
- if ((r != -ENOMEM) && (!quiet))
+ if (r < 0) {
+ dbus_error_free(&error);
+
+ if (!quiet)
puts("unknown");
- goto finish;
+ return 0;
}
if (!dbus_message_get_args(reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_unref(reply);
- r = bus_method_call_with_reply (
+ reply = NULL;
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
path,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &property,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0) {
+ if (!quiet)
+ puts("unknown");
+ return 0;
+ }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return r;
}
dbus_message_iter_recurse(&iter, &sub);
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return r;
}
dbus_message_iter_get_basic(&sub, &state);
if (!quiet)
puts(state);
- if (strv_find(check_states, state))
- r = 0;
- else
- r = 3; /* According to LSB: "program is not running" */
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- return r;
+ return strv_find(check_states, state) ? 1 : 0;
}
static void check_triggering_units(
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusMessageIter iter, sub;
- char *service_trigger = NULL;
const char *interface = "org.freedesktop.systemd1.Unit",
- *triggered_by_property = "TriggeredBy";
-
+ *load_state_property = "LoadState",
+ *triggered_by_property = "TriggeredBy",
+ *state;
char _cleanup_free_ *unit_path = NULL, *n = NULL;
bool print_warning_label = true;
int r;
return;
}
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ unit_path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &load_state_property,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return;
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+ log_error("Failed to parse reply.");
+ return;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+ log_error("Failed to parse reply.");
+ return;
+ }
+
+ dbus_message_iter_get_basic(&sub, &state);
+
+ if (streq(state, "masked"))
+ return;
+
+ dbus_message_unref(reply);
+ reply = NULL;
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
unit_path,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &triggered_by_property,
DBUS_TYPE_INVALID);
- if (r)
+ if (r < 0)
return;
if (!dbus_message_iter_init(reply, &iter) ||
sub = iter;
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- char **check_states = NULL;
+ const char * const check_states[] = {
+ "active",
+ "reloading",
+ NULL
+ };
+ const char *service_trigger;
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
dbus_message_iter_get_basic(&sub, &service_trigger);
- check_states = strv_new("active", "reloading", NULL);
- r = check_one_unit(bus, service_trigger, check_states, true);
- strv_free(check_states);
+ r = check_one_unit(bus, service_trigger, (char**) check_states, true);
if (r < 0)
return;
- if (r == 0) {
+ if (r > 0) {
if (print_warning_label) {
log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
print_warning_label = false;
}
+
log_warning(" %s", service_trigger);
}
Set *s) {
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ char *n;
const char *path;
int r;
- _cleanup_free_ char *n, *p = NULL;
assert(method);
assert(name);
n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
if (s) {
+ char *p;
+
p = strdup(path);
if (!p)
return log_oom();
r = set_put(s, p);
if (r < 0) {
+ free(p);
log_error("Failed to add path to set.");
return r;
}
-
- p = NULL;
}
return 0;
}
+static const struct {
+ const char *target;
+ const char *verb;
+ const char *mode;
+} action_table[_ACTION_MAX] = {
+ [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
+ [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
+ [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
+ [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
+ [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
+ [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
+ [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
+ [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
+ [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
+ [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
+ [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
+ [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
+};
+
static enum action verb_to_action(const char *verb) {
- if (streq(verb, "halt"))
- return ACTION_HALT;
- else if (streq(verb, "poweroff"))
- return ACTION_POWEROFF;
- else if (streq(verb, "reboot"))
- return ACTION_REBOOT;
- else if (streq(verb, "kexec"))
- return ACTION_KEXEC;
- else if (streq(verb, "rescue"))
- return ACTION_RESCUE;
- else if (streq(verb, "emergency"))
- return ACTION_EMERGENCY;
- else if (streq(verb, "default"))
- return ACTION_DEFAULT;
- else if (streq(verb, "exit"))
- return ACTION_EXIT;
- else if (streq(verb, "suspend"))
- return ACTION_SUSPEND;
- else if (streq(verb, "hibernate"))
- return ACTION_HIBERNATE;
- else if (streq(verb, "hybrid-sleep"))
- return ACTION_HYBRID_SLEEP;
- else
- return ACTION_INVALID;
+ enum action i;
+
+ for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
+ if (action_table[i].verb && streq(verb, action_table[i].verb))
+ return i;
+ return ACTION_INVALID;
}
static int start_unit(DBusConnection *bus, char **args) {
- static const char * const table[_ACTION_MAX] = {
- [ACTION_HALT] = SPECIAL_HALT_TARGET,
- [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
- [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
- [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
- [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
- [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
- [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
- [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
- [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
- [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
- [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
- [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
- [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
- [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
- [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
- };
-
int r, ret = 0;
const char *method, *mode, *one_name;
- Set *s = NULL;
- DBusError error;
+ Set _cleanup_set_free_free_ *s = NULL;
+ DBusError _cleanup_dbus_error_free_ error;
char **name;
dbus_error_init(&error);
ask_password_agent_open_if_enabled();
if (arg_action == ACTION_SYSTEMCTL) {
+ enum action action;
method =
streq(args[0], "stop") ||
streq(args[0], "condstop") ? "StopUnit" :
streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
"StartUnit";
+ action = verb_to_action(args[0]);
- mode =
- (streq(args[0], "isolate") ||
- streq(args[0], "rescue") ||
- streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
+ mode = streq(args[0], "isolate") ? "isolate" :
+ action_table[action].mode ?: arg_job_mode;
- one_name = table[verb_to_action(args[0])];
+ one_name = action_table[action].target;
} else {
- assert(arg_action < ELEMENTSOF(table));
- assert(table[arg_action]);
+ assert(arg_action < ELEMENTSOF(action_table));
+ assert(action_table[arg_action].target);
method = "StartUnit";
- mode = (arg_action == ACTION_EMERGENCY ||
- arg_action == ACTION_RESCUE ||
- arg_action == ACTION_RUNLEVEL2 ||
- arg_action == ACTION_RUNLEVEL3 ||
- arg_action == ACTION_RUNLEVEL4 ||
- arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
-
- one_name = table[arg_action];
+ mode = action_table[arg_action].mode;
+ one_name = action_table[arg_action].target;
}
if (!arg_no_block) {
ret = enable_wait_for_jobs(bus);
if (ret < 0) {
log_error("Could not watch jobs: %s", strerror(-ret));
- goto finish;
+ return ret;
}
s = set_new(string_hash_func, string_compare_func);
- if (!s) {
- ret = log_oom();
- goto finish;
- }
+ if (!s)
+ return log_oom();
}
if (one_name) {
if (!arg_no_block) {
r = wait_for_jobs(bus, s);
- if (r < 0) {
- ret = r;
- goto finish;
- }
+ if (r < 0)
+ return r;
/* When stopping units, warn if they can still be triggered by
* another active unit (socket, path, timer) */
}
}
-finish:
- set_free_free(s);
- dbus_error_free(&error);
-
return ret;
}
const char *method;
dbus_bool_t interactive = true;
+ if (!bus)
+ return -EIO;
+
polkit_agent_open_if_enabled();
switch (a) {
return -EINVAL;
}
- return bus_method_call_with_reply (
+ return bus_method_call_with_reply(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
#endif
}
+static int check_inhibitors(DBusConnection *bus, enum action a) {
+#ifdef HAVE_LOGIND
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ DBusMessageIter iter, sub, sub2;
+ int r;
+ unsigned c = 0;
+ _cleanup_strv_free_ char **sessions = NULL;
+ char **s;
+
+ if (!bus)
+ return 0;
+
+ if (arg_ignore_inhibitors || arg_force > 0)
+ return 0;
+
+ if (arg_when > 0)
+ return 0;
+
+ if (geteuid() == 0)
+ return 0;
+
+ if (!on_tty())
+ return 0;
+
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ListInhibitors",
+ &reply,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ /* If logind is not around, then there are no inhibitors... */
+ return 0;
+
+ 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;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *what, *who, *why, *mode;
+ uint32_t uid, pid;
+ _cleanup_strv_free_ char **sv = NULL;
+ _cleanup_free_ char *comm = NULL, *user = NULL;
+
+ 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, &what, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
+ log_error("Failed to parse reply.");
+ return -EIO;
+ }
+
+ if (!streq(mode, "block"))
+ goto next;
+
+ sv = strv_split(what, ":");
+ if (!sv)
+ return log_oom();
+
+ if (!strv_contains(sv,
+ a == ACTION_HALT ||
+ a == ACTION_POWEROFF ||
+ a == ACTION_REBOOT ||
+ a == ACTION_KEXEC ? "shutdown" : "sleep"))
+ goto next;
+
+ get_process_comm(pid, &comm);
+ user = uid_to_name(uid);
+ log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
+ who, (unsigned long) pid, strna(comm), strna(user), why);
+ c++;
+
+ next:
+ dbus_message_iter_next(&sub);
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ /* Check for current sessions */
+ sd_get_sessions(&sessions);
+ STRV_FOREACH(s, sessions) {
+ uid_t uid;
+ _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
+
+ if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
+ continue;
+
+ if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
+ continue;
+
+ if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
+ continue;
+
+ sd_session_get_tty(*s, &tty);
+ sd_session_get_seat(*s, &seat);
+ sd_session_get_service(*s, &service);
+ user = uid_to_name(uid);
+
+ log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
+ c++;
+ }
+
+ if (c <= 0)
+ return 0;
+
+ log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
+ action_table[a].verb);
+
+ return -EPERM;
+#else
+ return 0;
+#endif
+}
+
static int start_special(DBusConnection *bus, char **args) {
enum action a;
int r;
a = verb_to_action(args[0]);
+ r = check_inhibitors(bus, a);
+ if (r < 0)
+ return r;
+
if (arg_force >= 2 && geteuid() != 0) {
log_error("Must be root.");
return -EPERM;
}
r = start_unit(bus, args);
- if (r >= 0)
+ if (r == EXIT_SUCCESS)
warn_wall(a);
return r;
}
static int check_unit_active(DBusConnection *bus, char **args) {
+ const char * const check_states[] = {
+ "active",
+ "reloading",
+ NULL
+ };
+
char **name;
int r = 3; /* According to LSB: "program is not running" */
assert(args);
STRV_FOREACH(name, args+1) {
- char **check_states = strv_new("active", "reloading", NULL);
- int state = check_one_unit(bus, *name, check_states, arg_quiet);
- strv_free(check_states);
+ int state;
+
+ state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
if (state < 0)
return state;
- if (state == 0)
+ if (state > 0)
r = 0;
}
}
static int check_unit_failed(DBusConnection *bus, char **args) {
+ const char * const check_states[] = {
+ "failed",
+ NULL
+ };
+
char **name;
int r = 1;
assert(args);
STRV_FOREACH(name, args+1) {
- char **check_states = strv_new("failed", NULL);
- int state = check_one_unit(bus, *name, check_states, arg_quiet);
- strv_free(check_states);
+ int state;
+
+ state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
if (state < 0)
return state;
- if (state == 0)
+ if (state > 0)
r = 0;
}
}
static int kill_unit(DBusConnection *bus, char **args) {
+ char **name;
int r = 0;
- char **name, *n;
+ assert(bus);
assert(args);
if (!arg_kill_who)
arg_kill_who = "all";
STRV_FOREACH(name, args+1) {
+ _cleanup_free_ char *n = NULL;
+
n = unit_name_mangle(*name);
- r = bus_method_call_with_reply (
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"KillUnit",
NULL,
NULL,
- DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_STRING, &arg_kill_who,
DBUS_TYPE_INT32, &arg_signal,
DBUS_TYPE_INVALID);
- free(n);
- if (r)
+ if (r < 0)
+ return r;
+ }
+ 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 *m = NULL, *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;
+
+ 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 (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
return -EIO;
- if (!(i->path = strdup(path)))
+ i->path = strdup(path);
+ if (!i->path)
return -ENOMEM;
if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
n++;
}
-
- if (!(i->argv = new0(char*, n+1)))
+ i->argv = new0(char*, n+1);
+ if (!i->argv)
return -ENOMEM;
n = 0;
dbus_message_iter_get_basic(&sub3, &s);
dbus_message_iter_next(&sub3);
- if (!(i->argv[n++] = strdup(s)))
+ i->argv[n] = strdup(s);
+ if (!i->argv[n])
return -ENOMEM;
+
+ n++;
}
if (!dbus_message_iter_next(&sub2) ||
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
char since2[FORMAT_TIMESTAMP_MAX], *s2;
const char *path;
+ int flags =
+ arg_all * OUTPUT_SHOW_ALL |
+ (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
+ on_tty() * OUTPUT_COLOR |
+ !arg_quiet * OUTPUT_WARN_CUTOFF |
+ arg_full * OUTPUT_FULL_WIDTH;
assert(i);
printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
LIST_FOREACH(exec, p, i->exec) {
- char *t;
+ _cleanup_free_ char *t = NULL;
bool good;
/* Only show exited processes here */
t = strv_join(p->argv, " ");
printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
- free(t);
good = is_clean_exit_lsb(p->code, p->status, NULL);
if (!good) {
printf("Main PID: %u", (unsigned) i->main_pid);
if (i->running) {
- char *t = NULL;
+ _cleanup_free_ char *t = NULL;
get_process_comm(i->main_pid, &t);
- if (t) {
+ if (t)
printf(" (%s)", t);
- free(t);
- }
} else if (i->exit_code > 0) {
printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
printf(";");
if (i->control_pid > 0) {
- char *t = NULL;
+ _cleanup_free_ char *t = NULL;
printf(" Control: %u", (unsigned) i->control_pid);
get_process_comm(i->control_pid, &t);
- if (t) {
+ if (t)
printf(" (%s)", t);
- free(t);
- }
}
printf("\n");
if (i->control_pid > 0)
extra[k++] = i->control_pid;
- show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, extra, k);
+ show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, extra, k, flags);
}
}
if (i->id && arg_transport != TRANSPORT_SSH) {
- int flags =
- arg_all * OUTPUT_SHOW_ALL |
- (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
- on_tty() * OUTPUT_COLOR |
- !arg_quiet * OUTPUT_WARN_CUTOFF;
-
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)
if (startswith(*p, "man:")) {
size_t k;
char *e = NULL;
- char *page = NULL, *section = NULL;
+ char _cleanup_free_ *page = NULL, *section = NULL;
const char *args[4] = { "man", NULL, NULL, NULL };
pid_t pid;
if (e) {
page = strndup((*p) + 4, e - *p - 4);
- if (!page) {
- log_oom();
- return;
- }
-
section = strndup(e + 1, *p + k - e - 2);
- if (!section) {
- free(page);
+ if (!page || !section) {
log_oom();
return;
}
pid = fork();
if (pid < 0) {
log_error("Failed to fork: %m");
- free(page);
- free(section);
continue;
}
_exit(EXIT_FAILURE);
}
- free(page);
- free(section);
-
wait_for_terminate(pid, NULL);
} else
log_info("Can't show: %s", *p);
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);
zero(info);
if (exec_status_info_deserialize(&sub, &info) >= 0) {
char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
- char *t;
+ char _cleanup_free_ *t;
t = strv_join(info.argv, " ");
info.status,
info.code == CLD_EXITED ? "" : "/",
strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
-
- free(t);
}
free(info.path);
}
static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
- DBusMessage *reply = NULL;
+ _cleanup_free_ DBusMessage *reply = NULL;
const char *interface = "";
int r;
DBusMessageIter iter, sub, sub2, sub3;
zero(info);
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
path,
NULL,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ 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.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
const char *name;
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
-
+ 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, &name, true) < 0) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
-
- if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
+ dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&sub2, &sub3);
r = print_property(name, &sub3);
else
r = status_property(name, &sub3, &info);
-
if (r < 0) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_next(&sub);
exec_status_info_free(p);
}
-finish:
- if (reply)
- dbus_message_unref(reply);
-
return r;
}
static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
- DBusMessage *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
const char *path = NULL;
- DBusError error;
+ DBusError _cleanup_dbus_error_free_ error;
int r;
dbus_error_init(&error);
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
NULL,
DBUS_TYPE_UINT32, &pid,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
+ return -EIO;
}
r = show_one(verb, bus, path, false, new_line);
+ return r;
+}
-finish:
- if (reply)
- dbus_message_unref(reply);
+static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) {
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ struct unit_info *unit_infos = NULL;
+ unsigned c = 0;
+ const struct unit_info *u;
+ int r;
- dbus_error_free(&error);
+ r = get_unit_list(bus, &reply, &unit_infos, &c);
+ if (r < 0)
+ return r;
- return r;
+ for (u = unit_infos; u < unit_infos + c; u++) {
+ char _cleanup_free_ *p = NULL;
+
+ if (!output_show_unit(u))
+ continue;
+
+ p = unit_dbus_path_from_name(u->id);
+ if (!p)
+ return log_oom();
+
+ printf("%s -> '%s'\n", u->id, p);
+
+ r = show_one(verb, bus, p, show_properties, new_line);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
}
static int show(DBusConnection *bus, char **args) {
int r, ret = 0;
- bool show_properties, new_line = false;
+ bool show_properties, show_status, new_line = false;
char **name;
assert(bus);
assert(args);
show_properties = streq(args[0], "show");
+ show_status = streq(args[0], "status");
if (show_properties)
pager_open_if_enabled();
- if (show_properties && strv_length(args) <= 1) {
- /* If not argument is specified inspect the manager
- * itself */
+ /* 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);
- }
+
+ if (show_status && strv_length(args) <= 1)
+ return show_all(args[0], bus, false, &new_line);
STRV_FOREACH(name, args+1) {
uint32_t id;
if (safe_atou32(*name, &id) < 0) {
- char *p, *n;
+ _cleanup_free_ char *p = NULL, *n = NULL;
/* Interpret as unit name */
n = unit_name_mangle(*name);
- p = unit_dbus_path_from_name(n ? n : *name);
- free(n);
+ if (!n)
+ 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);
- free(p);
-
if (r != 0)
ret = r;
} else if (show_properties) {
+ _cleanup_free_ char *p = NULL;
/* Interpret as job id */
-
- char *p;
if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
return log_oom();
r = show_one(args[0], bus, p, show_properties, &new_line);
- free(p);
-
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;
}
static int dump(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
+ _cleanup_free_ DBusMessage *reply = NULL;
DBusError error;
int r;
const char *text;
pager_open_if_enabled();
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
&reply,
NULL,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ 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));
- r = -EIO;
- goto finish;
+ dbus_error_free(&error);
+ return -EIO;
}
fputs(text, stdout);
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int snapshot(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusError error;
int r;
dbus_bool_t cleanup = FALSE;
DBusMessageIter iter, sub;
const char
- *name = "", *path, *id,
+ *path, *id,
*interface = "org.freedesktop.systemd1.Unit",
*property = "Id";
- char *n;
+ _cleanup_free_ char *n = NULL;
dbus_error_init(&error);
if (strv_length(args) > 1)
- name = args[1];
+ n = snapshot_name_mangle(args[1]);
+ else
+ n = strdup("");
+ if (!n)
+ return log_oom();
- n = unit_name_mangle(name);
r = bus_method_call_with_reply (
bus,
"org.freedesktop.systemd1",
"CreateSnapshot",
&reply,
NULL,
- DBUS_TYPE_STRING, n ? (const char**) &n : &name,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_BOOLEAN, &cleanup,
DBUS_TYPE_INVALID);
- free(n);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
+ dbus_error_free(&error);
+ return -EIO;
}
dbus_message_unref(reply);
+ reply = NULL;
+
r = bus_method_call_with_reply (
bus,
"org.freedesktop.systemd1",
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &property,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&iter, &sub);
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_get_basic(&sub, &id);
if (!arg_quiet)
puts(id);
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int delete_snapshot(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
- int r = 0;
- DBusError error;
char **name;
assert(args);
- dbus_error_init(&error);
-
STRV_FOREACH(name, args+1) {
- const char *path = NULL;
- char *n;
+ _cleanup_free_ char *n = NULL;
+ int r;
- n = unit_name_mangle(*name);
- r = bus_method_call_with_reply (
+ n = snapshot_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",
- "GetUnit",
- &reply,
- NULL,
- DBUS_TYPE_STRING, n ? &n : name,
- DBUS_TYPE_INVALID);
- free(n);
- if (r)
- goto finish;
-
- if (!dbus_message_get_args(reply, &error,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse reply: %s", bus_error_message(&error));
- r = -EIO;
- dbus_message_unref(reply);
- dbus_error_free(&error);
- goto finish;
- }
- dbus_message_unref(reply);
-
- r = bus_method_call_with_reply (
- bus,
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.systemd1.Snapshot",
- "Remove",
+ "RemoveSnapshot",
NULL,
NULL,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
}
-finish:
- return r;
+ return 0;
}
static int daemon_reload(DBusConnection *bus, char **args) {
/* "daemon-reload" */ "Reload";
}
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
/* On reexecution, we expect a disconnect, not
* a reply */
r = 0;
- else if (r)
+ else if (r < 0)
log_error("Failed to issue method call: %s", bus_error_message(&error));
- dbus_error_free(&error);
+ dbus_error_free(&error);
return r;
}
static int reset_failed(DBusConnection *bus, char **args) {
int r = 0;
- char **name, *n;
+ char **name;
if (strv_length(args) <= 1)
return daemon_reload(bus, args);
STRV_FOREACH(name, args+1) {
+ _cleanup_free_ char *n;
+
n = unit_name_mangle(*name);
- r = bus_method_call_with_reply (
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"ResetFailedUnit",
NULL,
NULL,
- DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_STRING, &n,
DBUS_TYPE_INVALID);
- free(n);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
}
-finish:
- return r;
+ return 0;
}
static int show_enviroment(DBusConnection *bus, char **args) {
- DBusMessage *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusMessageIter iter, sub, sub2;
int r;
const char
pager_open_if_enabled();
- r = bus_method_call_with_reply (
+ r = bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &property,
DBUS_TYPE_INVALID);
- if (r)
- goto finish;
+ if (r < 0)
+ return r;
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&iter, &sub);
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_recurse(&sub, &sub2);
if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_iter_get_basic(&sub2, &text);
- printf("%s\n", text);
+ puts(text);
dbus_message_iter_next(&sub2);
}
- r = 0;
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- return r;
+ return 0;
}
static int switch_root(DBusConnection *bus, char **args) {
if (!init)
init = strdup("");
-
- if (!init)
- return log_oom();
-
}
+ if (!init)
+ return log_oom();
log_debug("switching root - root: %s; init: %s", root, init);
- return bus_method_call_with_reply (
+ return bus_method_call_with_reply(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
int r;
assert(bus);
+ assert(args);
dbus_error_init(&error);
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));
- r = -EIO;
- goto finish;
+ dbus_error_free(&error);
+ return -EIO;
}
- r = 0;
-
-finish:
- dbus_error_free(&error);
- return r;
+ return 0;
}
static int enable_sysv_units(char **args) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0, i;
int carries_install_info = -1;
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
int r;
- DBusError error;
- char **mangled_names = NULL;
+ DBusError _cleanup_dbus_error_free_ error;
+ char _cleanup_strv_free_ **mangled_names = NULL;
+
+ dbus_error_init(&error);
r = enable_sysv_units(args);
if (r < 0)
if (!args[1])
return 0;
- dbus_error_init(&error);
-
if (!bus || avoid_bus()) {
if (streq(verb, "enable")) {
r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
}
if (carries_install_info == 0)
- log_warning(
-"The unit files have no [Install] section. They are not meant to be enabled\n"
-"using systemctl.\n"
-"Possible reasons for having this kind of units are:\n"
-"1) A unit may be statically enabled by being symlinked from another unit's\n"
-" .wants/ or .requires/ directory.\n"
-"2) A unit's purpose may be to act as a helper for some other unit which has\n"
-" a requirement dependency on it.\n"
-"3) A unit may be started when needed via activation (socket, path, timer,\n"
-" D-Bus, udev, scripted systemctl call, ...).\n");
+ log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
+ "using systemctl.\n"
+ "Possible reasons for having this kind of units are:\n"
+ "1) A unit may be statically enabled by being symlinked from another unit's\n"
+ " .wants/ or .requires/ directory.\n"
+ "2) A unit's purpose may be to act as a helper for some other unit which has\n"
+ " a requirement dependency on it.\n"
+ "3) A unit may be started when needed via activation (socket, path, timer,\n"
+ " D-Bus, udev, scripted systemctl call, ...).\n");
finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
unit_file_changes_free(changes, n_changes);
- dbus_error_free(&error);
-
- strv_free(mangled_names);
-
return r;
}
static int unit_is_enabled(DBusConnection *bus, char **args) {
- DBusError error;
+ DBusError _cleanup_dbus_error_free_ error;
int r;
- DBusMessage *reply = NULL;
+ DBusMessage _cleanup_dbus_message_unref_ *reply = NULL;
bool enabled;
char **name;
UnitFileState state;
state = unit_file_get_state(arg_scope, arg_root, *name);
- if (state < 0) {
- r = state;
- goto finish;
- }
+ if (state < 0)
+ return state;
if (state == UNIT_FILE_ENABLED ||
state == UNIT_FILE_ENABLED_RUNTIME ||
DBUS_TYPE_STRING, name,
DBUS_TYPE_INVALID);
if (r)
- goto finish;
+ return r;
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_STRING, &s,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
+ return -EIO;
}
dbus_message_unref(reply);
}
}
- r = enabled ? 0 : 1;
-
-finish:
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
- return r;
+ return enabled ? 0 : 1;
}
static int systemctl_help(void) {
" pending\n"
" --ignore-dependencies\n"
" When queueing a new job, ignore all its dependencies\n"
+ " -i --ignore-inhibitors\n"
+ " When shutting down or sleeping, ignore inhibitors\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
" -H --host=[USER@]HOST\n"
" --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"
" 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"
- " help [NAME...|PID...] Show manual for one or more units\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"
- " load [NAME...] Load one or more units\n\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"
"Unit File Commands:\n"
" list-unit-files List installed unit files\n"
" enable [NAME...] Enable one or more unit files\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"
enum {
ARG_FAIL = 0x100,
+ ARG_IRREVERSIBLE,
ARG_IGNORE_DEPENDENCIES,
ARG_VERSION,
ARG_USER,
ARG_NO_LEGEND,
ARG_NO_PAGER,
ARG_NO_WALL,
- ARG_ORDER,
- ARG_REQUIRE,
ARG_ROOT,
ARG_FULL,
ARG_NO_RELOAD,
{ "failed", no_argument, NULL, ARG_FAILED },
{ "full", no_argument, NULL, ARG_FULL },
{ "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-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 },
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) {
switch (c) {
case ARG_VERSION:
puts(PACKAGE_STRING);
- puts(DISTRIBUTION);
puts(SYSTEMD_FEATURES);
return 0;
log_info("Use -t help to see a list of allowed values.");
return -EINVAL;
case 'p': {
- char **l;
+ char *word, *state;
+ size_t size;
+ /* Make sure that if the empty property list
+ was specified, we won't show any properties. */
+ const char *source = isempty(optarg) ? " " : optarg;
+
+ FOREACH_WORD_SEPARATOR(word, size, source, ",", state) {
+ char _cleanup_free_ *prop;
+ char **tmp;
+
+ prop = strndup(word, size);
+ if (!prop)
+ return -ENOMEM;
- if (!(l = strv_append(arg_property, optarg)))
- return -ENOMEM;
+ tmp = strv_append(arg_property, prop);
+ if (!tmp)
+ return -ENOMEM;
- strv_free(arg_property);
- arg_property = l;
+ strv_free(arg_property);
+ arg_property = tmp;
+ }
/* If the user asked for a particular
* property, show it to him, even if it is
* empty. */
arg_all = true;
+
break;
}
arg_job_mode = "fail";
break;
+ case ARG_IRREVERSIBLE:
+ arg_job_mode = "replace-irreversibly";
+ break;
+
case ARG_IGNORE_DEPENDENCIES:
arg_job_mode = "ignore-dependencies";
break;
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;
}
break;
+ case 'i':
+ arg_ignore_inhibitors = true;
+ break;
+
case '?':
return -EINVAL;
}
static int talk_upstart(void) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+ DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
+ DBusError _cleanup_dbus_error_free_ error;
int previous, rl, r;
char
env1_buf[] = "RUNLEVEL=X",
r = 1;
finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
if (bus) {
dbus_connection_flush(bus);
dbus_connection_close(bus);
dbus_connection_unref(bus);
}
- dbus_error_free(&error);
-
return r;
}
{ "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 },
{ "is-failed", MORE, 2, check_unit_failed },
{ "show", MORE, 1, show },
- { "status", MORE, 2, show },
+ { "status", MORE, 1, 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 },
{ "unmask", MORE, 2, enable_unit },
{ "link", MORE, 2, enable_unit },
{ "switch-root", MORE, 2, switch_root },
+ { "list-dependencies", LESS, 2, list_dependencies },
};
int left;
}
static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
- int fd;
+ int _cleanup_close_ fd;
struct msghdr msghdr;
struct iovec iovec[2];
union sockaddr_union sockaddr;
}
msghdr.msg_iov = iovec;
- if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
- close_nointr_nofail(fd);
+ if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
return -errno;
- }
- close_nointr_nofail(fd);
return 0;
}
static int halt_main(DBusConnection *bus) {
int r;
+ r = check_inhibitors(bus, arg_action);
+ if (r < 0)
+ return r;
+
if (geteuid() != 0) {
/* Try logind if we are a normal user and no special
* mode applies. Maybe PolicyKit allows us to shutdown
if (arg_when <= 0 &&
!arg_dry &&
- !arg_force &&
+ arg_force <= 0 &&
(arg_action == ACTION_POWEROFF ||
arg_action == ACTION_REBOOT)) {
r = reboot_with_logind(bus, arg_action);
}
if (arg_when > 0) {
- char *m;
+ char _cleanup_free_ *m;
m = strv_join(arg_wall, " ");
r = send_shutdownd(arg_when,
arg_dry,
!arg_no_wall,
m);
- free(m);
if (r < 0)
log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
int main(int argc, char*argv[]) {
int r, retval = EXIT_FAILURE;
DBusConnection *bus = NULL;
- DBusError error;
+ DBusError _cleanup_dbus_error_free_ error;
dbus_error_init(&error);
dbus_connection_unref(bus);
}
- dbus_error_free(&error);
-
dbus_shutdown();
strv_free(arg_property);