#include <sys/reboot.h>
#include <stdio.h>
#include <getopt.h>
+#include <locale.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <systemd/sd-daemon.h>
#include <systemd/sd-shutdown.h>
+#include <systemd/sd-login.h>
#include "log.h"
#include "util.h"
#include "install.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 char **arg_property = NULL;
static bool arg_all = false;
static const char *arg_job_mode = "replace";
static bool arg_no_legend = false;
static bool arg_no_pager = false;
static bool arg_no_wtmp = false;
-static bool arg_no_sync = 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;
static bool arg_runtime = false;
static char **arg_wall = NULL;
static const char *arg_kill_who = NULL;
-static const char *arg_kill_mode = NULL;
static int arg_signal = SIGTERM;
static const char *arg_root = NULL;
static usec_t arg_when = 0;
ACTION_EXIT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP,
ACTION_RUNLEVEL2,
ACTION_RUNLEVEL3,
ACTION_RUNLEVEL4,
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,
TRANSPORT_POLKIT
} arg_transport = TRANSPORT_NORMAL;
static const char *arg_host = NULL;
-static bool arg_follow = false;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static int daemon_reload(DBusConnection *bus, char **args);
static void halt_now(enum action a);
-static bool on_tty(void) {
- static int t = -1;
-
- /* Note that this is invoked relatively early, before we start
- * the pager. That means the value we return reflects whether
- * we originally were started on a tty, not if we currently
- * are. But this is intended, since we want colour and so on
- * when run in our own pager. */
-
- if (_unlikely_(t < 0))
- t = isatty(STDOUT_FILENO) > 0;
-
- return t;
-}
-
static void pager_open_if_enabled(void) {
- /* Cache result before we open the pager */
- on_tty();
-
if (arg_no_pager)
return;
}
#endif
-static const char *ansi_highlight_red(bool b) {
+static const char *ansi_highlight(bool b) {
if (!on_tty())
return "";
- return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
+ return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
}
-static const char *ansi_highlight_green(bool b) {
+static const char *ansi_highlight_red(bool b) {
if (!on_tty())
return "";
- return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
+ return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
}
-static bool error_is_no_service(const DBusError *error) {
- assert(error);
-
- if (!dbus_error_is_set(error))
- return false;
-
- if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
- return true;
+static const char *ansi_highlight_green(bool b) {
- if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
- return true;
+ if (!on_tty())
+ return "";
- return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
+ return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
}
static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
static void warn_wall(enum action a) {
static const char *table[_ACTION_MAX] = {
- [ACTION_HALT] = "The system is going down for system halt NOW!",
- [ACTION_REBOOT] = "The system is going down for reboot NOW!",
- [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
- [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
- [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
- [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
+ [ACTION_HALT] = "The system is going down for system halt NOW!",
+ [ACTION_REBOOT] = "The system is going down for reboot NOW!",
+ [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
+ [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
+ [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
+ [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
+ [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
};
if (arg_no_wall)
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;
}
return (!arg_type || ((dot = strrchr(u->id, '.')) &&
streq(dot+1, arg_type))) &&
- (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
+ (!arg_load_state || streq(u->load_state, arg_load_state)) &&
+ (arg_all || !(streq(u->active_state, "inactive")
+ || u->following[0]) || u->job_id > 0);
}
static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
const struct unit_info *u;
+ int job_count = 0;
max_id_len = sizeof("UNIT")-1;
active_len = sizeof("ACTIVE")-1;
max_id_len = MAX(max_id_len, strlen(u->id));
active_len = MAX(active_len, strlen(u->active_state));
sub_len = MAX(sub_len, strlen(u->sub_state));
- if (u->job_id != 0)
+ if (u->job_id != 0) {
job_len = MAX(job_len, strlen(u->job_type));
+ job_count++;
+ }
}
if (!arg_full) {
unsigned basic_len;
id_len = MIN(max_id_len, 25);
- basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
+ basic_len = 5 + id_len + 5 + active_len + sub_len;
+ if (job_count)
+ basic_len += job_len + 1;
if (basic_len < (unsigned) columns()) {
unsigned extra_len, incr;
extra_len = columns() - basic_len;
} else
id_len = max_id_len;
- if (!arg_no_legend) {
- printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
- active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
- if (!arg_full && arg_no_pager)
- printf("%.*s\n", desc_len, "DESCRIPTION");
- else
- printf("%s\n", "DESCRIPTION");
- }
-
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;
if (!output_show_unit(u))
continue;
+ if (!n_shown && !arg_no_legend) {
+ printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
+ active_len, "ACTIVE", sub_len, "SUB");
+ if (job_count)
+ printf("%-*s ", job_len, "JOB");
+ if (!arg_full && arg_no_pager)
+ printf("%.*s\n", desc_len, "DESCRIPTION");
+ else
+ printf("%s\n", "DESCRIPTION");
+ }
+
n_shown++;
if (streq(u->load_state, "error")) {
e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
- printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
+ printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s",
id_len, e ? e : u->id,
on_loaded, u->load_state, off_loaded,
on_active, active_len, u->active_state,
sub_len, u->sub_state, off_active,
- job_len, u->job_id ? u->job_type : "");
+ job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
if (!arg_full && arg_no_pager)
printf("%.*s\n", desc_len, u->description);
else
printf("%s\n", u->description);
-
- free(e);
}
if (!arg_no_legend) {
- printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
- "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
- "SUB = The low-level unit activation state, values depend on unit type.\n"
- "JOB = Pending job for the unit.\n");
+ const char *on, *off;
+
+ if (n_shown) {
+ printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
+ "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
+ "SUB = The low-level unit activation state, values depend on unit type.\n");
+ if (job_count)
+ printf("JOB = Pending job for the unit.\n");
+ puts("");
+ on = ansi_highlight(true);
+ off = ansi_highlight(false);
+ } else {
+ on = ansi_highlight_red(true);
+ off = ansi_highlight_red(false);
+ }
if (arg_all)
- printf("\n%u units listed.\n", n_shown);
+ printf("%s%u loaded units listed.%s\n"
+ "To show all installed unit files use 'systemctl list-unit-files'.\n",
+ on, n_shown, off);
else
- printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
+ printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
+ "To show all installed unit files use 'systemctl list-unit-files'.\n",
+ on, n_shown, off);
}
}
-static int list_units(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+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;
-
- dbus_error_init(&error);
assert(bus);
+ assert(unit_infos);
+ assert(c);
- pager_open_if_enabled();
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits"))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
+ 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) ||
+ 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);
- r = 0;
+ return 0;
+}
-finish:
- if (m)
- dbus_message_unref(m);
+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;
- if (reply)
- dbus_message_unref(reply);
+ pager_open_if_enabled();
- free(unit_infos);
+ r = get_unit_list(bus, &reply, &unit_infos, &c);
+ if (r < 0)
+ return r;
- dbus_error_free(&error);
+ if (c > 0)
+ output_units_list(unit_infos, c);
- return r;
+ 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;
if (u->state == UNIT_FILE_MASKED ||
u->state == UNIT_FILE_MASKED_RUNTIME ||
- u->state == UNIT_FILE_DISABLED) {
+ u->state == UNIT_FILE_DISABLED ||
+ u->state == UNIT_FILE_INVALID) {
on = ansi_highlight_red(true);
off = ansi_highlight_red(false);
} else if (u->state == UNIT_FILE_ENABLED) {
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 *m = NULL, *reply = NULL;
- DBusError error;
- 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;
-
- dbus_error_init(&error);
+ int r;
pager_open_if_enabled();
Iterator i;
h = hashmap_new(string_hash_func, string_compare_func);
- if (!h) {
- log_error("Out of memory");
- return -ENOMEM;
- }
+ if (!h)
+ return log_oom();
r = unit_file_get_list(arg_scope, arg_root, h);
if (r < 0) {
units = new(UnitFileList, n_units);
if (!units) {
unit_file_list_free(h);
- log_error("Out of memory");
- return -ENOMEM;
+ return log_oom();
}
HASHMAP_FOREACH(u, h, i) {
hashmap_free(h);
} else {
- assert(bus);
-
- m = dbus_message_new_method_call(
+ r = bus_method_call_with_reply(
+ bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "ListUnitFiles");
- if (!m) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- 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;
- }
+ "ListUnitFiles",
+ &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.");
- 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 (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- free(units);
-
- dbus_error_free(&error);
-
- 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=\"darkgrey\"]",
- "Conflicts", "[color=\"red\"]",
- "ConflictedBy", "[color=\"red\"]",
- "After", "[color=\"green\"]"
- };
-
- const char *c = NULL;
- unsigned i;
-
- assert(name);
- assert(prop);
- assert(iter);
+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 = 0; i < ELEMENTSOF(colors); i += 2)
- if (streq(colors[i], prop)) {
- c = colors[i+1];
- break;
+ 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;
-
- 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;
- }
+ if(arg_full){
+ printf("%s\n", name);
+ return 0;
}
+ n = ellipsize(name, max_len-len, 100);
+ if(!n)
+ return log_oom();
+
+ printf("%s\n", n);
return 0;
}
-static int dot_one(DBusConnection *bus, const char *name, const char *path) {
- DBusMessage *m = NULL, *reply = NULL;
+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";
+
+ _cleanup_free_ char *path;
const char *interface = "org.freedesktop.systemd1.Unit";
- int r;
- DBusError error;
- DBusMessageIter iter, sub, sub2, sub3;
- assert(bus);
- assert(path);
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ DBusMessageIter iter, sub, sub2, sub3;
- dbus_error_init(&error);
+ int r = 0;
+ char **ret = NULL;
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.DBus.Properties",
- "GetAll"))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
+ assert(bus);
+ assert(name);
+ assert(deps);
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
+ path = unit_dbus_path_from_name(name);
+ if (path == NULL) {
+ r = -EINVAL;
goto finish;
}
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
+ 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);
-
- if (dot_one_property(name, prop, &sub3)) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
-
dbus_message_iter_next(&sub);
- }
- r = 0;
+ if (!nulstr_contains(dependencies, prop))
+ continue;
-finish:
- if (m)
- dbus_message_unref(m);
+ 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);
- if (reply)
- dbus_message_unref(reply);
+ while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
+ const char *s;
- dbus_error_free(&error);
+ 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 *m = NULL, *reply = NULL;
- DBusError error;
- 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);
+}
- dbus_error_init(&error);
+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;
- assert(bus);
+ u = strv_append(units, name);
+ if (!u)
+ return log_oom();
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits"))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
+ r = list_dependencies_get_dependencies(bus, name, &deps);
+ if (r < 0)
+ return r;
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- 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_STRUCT) {
- log_error("Failed to parse reply.");
- r = -EIO;
- goto finish;
- }
-
- 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;
+ 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");
-
- log_info(" Color legend: black = Requires\n"
- " dark blue = Requisite\n"
- " dark grey = Wants\n"
- " red = Conflicts\n"
- " green = After\n");
+ return 0;
+}
- 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");
+static int list_dependencies(DBusConnection *bus, char **args) {
+ _cleanup_free_ char *unit = NULL;
+ const char *u;
- r = 0;
+ assert(bus);
-finish:
- if (m)
- dbus_message_unref(m);
+ if (args[1]) {
+ unit = unit_name_mangle(args[1]);
+ if (!unit)
+ return log_oom();
+ u = unit;
+ } else
+ u = SPECIAL_DEFAULT_TARGET;
- if (reply)
- dbus_message_unref(reply);
+ pager_open_if_enabled();
- dbus_error_free(&error);
+ puts(u);
- return r;
+ return list_dependencies_one(bus, u, 0, NULL, 0);
}
static int list_jobs(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
- int r;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusMessageIter iter, sub, sub2;
unsigned k = 0;
-
- dbus_error_init(&error);
-
- assert(bus);
+ int r;
pager_open_if_enabled();
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListJobs"))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListJobs",
+ &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.");
- 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 (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int load_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL;
- DBusError error;
- int r;
char **name;
- dbus_error_init(&error);
-
- assert(bus);
assert(args);
STRV_FOREACH(name, args+1) {
- DBusMessage *reply;
- bool b;
- char *n;
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LoadUnit"))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
+ _cleanup_free_ char *n = NULL;
+ int r;
n = unit_name_mangle(*name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? &n : name,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- 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_message_unref(m);
- dbus_message_unref(reply);
+ if (!n)
+ return log_oom();
- m = reply = NULL;
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LoadUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
}
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int cancel_job(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
- int r;
char **name;
- dbus_error_init(&error);
-
- assert(bus);
assert(args);
if (strv_length(args) <= 1)
return daemon_reload(bus, args);
STRV_FOREACH(name, args+1) {
- unsigned id;
- const char *path;
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetJob"))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
+ uint32_t id;
+ int r;
- if ((r = safe_atou(*name, &id)) < 0) {
+ r = safe_atou32(*name, &id);
+ if (r < 0) {
log_error("Failed to parse job id: %s", strerror(-r));
- goto finish;
- }
-
- assert_cc(sizeof(uint32_t) == sizeof(id));
- if (!dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- 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;
- goto finish;
- }
-
- dbus_message_unref(m);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.systemd1.Job",
- "Cancel"))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- dbus_message_unref(reply);
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
+ return r;
}
- dbus_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "CancelJob",
+ NULL,
+ NULL,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
}
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
- DBusMessage *m = NULL, *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;
- bool k;
+ _cleanup_free_ char *n = NULL;
+ int r;
/* We ignore all errors here, since this is used to show a warning only */
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit");
- if (!m)
- goto finish;
-
n = unit_name_mangle(unit);
- k = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
- DBUS_TYPE_INVALID);
- free(n);
- if (!k)
- goto finish;
+ if (!n)
+ return log_oom();
- reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL);
- if (!reply)
- goto finish;
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_INVALID);
+ 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(m);
- m = dbus_message_new_method_call(
+ dbus_message_unref(reply);
+ reply = NULL;
+
+ r = bus_method_call_with_reply(
+ bus,
"org.freedesktop.systemd1",
path,
"org.freedesktop.DBus.Properties",
- "Get");
- if (!m)
- goto finish;
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_STRING, &property,
- DBUS_TYPE_INVALID)) {
- goto finish;
- }
-
- dbus_message_unref(reply);
- reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL);
- if (!reply)
- goto finish;
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &property,
+ DBUS_TYPE_INVALID);
+ 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 (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
return b;
}
typedef struct WaitData {
Set *set;
+
+ char *name;
char *result;
} 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 (*result)
+ if (!isempty(result))
d->result = strdup(result);
- goto finish;
+ if (!isempty(unit))
+ d->name = strdup(unit);
+
+ 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;
}
}
static int wait_for_jobs(DBusConnection *bus, Set *s) {
- int r;
+ int r = 0;
WaitData d;
assert(bus);
zero(d);
d.set = s;
- if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
- log_error("Failed to add filter.");
- r = -ENOMEM;
- goto finish;
- }
+ if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
+ return log_oom();
- while (!set_isempty(s) &&
- dbus_connection_read_write_dispatch(bus, -1))
- ;
+ while (!set_isempty(s)) {
- if (!arg_quiet && d.result) {
- if (streq(d.result, "timeout"))
- log_error("Job timed out.");
- else if (streq(d.result, "canceled"))
- log_error("Job canceled.");
- else if (streq(d.result, "dependency"))
- log_error("A dependency job failed. See system journal for details.");
- else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
- log_error("Job failed. See system journal and 'systemctl status' for details.");
- }
+ if (!dbus_connection_read_write_dispatch(bus, -1)) {
+ log_error("Disconnected from bus.");
+ return -ECONNREFUSED;
+ }
- if (streq_ptr(d.result, "timeout"))
- r = -ETIME;
- else if (streq_ptr(d.result, "canceled"))
- r = -ECANCELED;
- else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
- r = -EIO;
- else
- r = 0;
+ if (!d.result)
+ goto free_name;
- free(d.result);
+ if (!arg_quiet) {
+ if (streq(d.result, "timeout"))
+ log_error("Job for %s timed out.", strna(d.name));
+ else if (streq(d.result, "canceled"))
+ log_error("Job for %s canceled.", strna(d.name));
+ else if (streq(d.result, "dependency"))
+ log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
+ else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
+ log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
+ }
-finish:
- /* This is slightly dirty, since we don't undo the filter registration. */
+ if (streq_ptr(d.result, "timeout"))
+ r = -ETIME;
+ else if (streq_ptr(d.result, "canceled"))
+ r = -ECANCELED;
+ else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
+ r = -EIO;
+ free(d.result);
+ d.result = NULL;
+
+ free_name:
+ free(d.name);
+ d.name = NULL;
+ }
+
+ dbus_connection_remove_filter(bus, wait_filter, &d);
return r;
}
-static int check_one_unit(DBusConnection *bus, char *name, bool quiet) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+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;
- int r = 3; /* According to LSB: "program is not running" */
- char *n;
- bool b;
+ const char *state, *path;
+ DBusError error;
+ int r;
- assert(bus);
assert(name);
dbus_error_init(&error);
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
n = unit_name_mangle(name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? &n : &name,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit",
+ &reply,
+ &error,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_INVALID);
+ if (r < 0) {
+ dbus_error_free(&error);
- reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
- if (!reply) {
- /* Hmm, cannot figure out anything about this unit... */
if (!quiet)
puts("unknown");
-
- goto finish;
+ return 0;
}
- if (!dbus_message_get_args(reply, &error,
+ if (!dbus_message_get_args(reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
- log_error("Failed to parse reply: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
-
- dbus_message_unref(m);
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.DBus.Properties",
- "Get");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_STRING, &property,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
+ log_error("Failed to parse reply.");
+ return -EIO;
}
dbus_message_unref(reply);
- 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;
+ reply = NULL;
+
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &property,
+ DBUS_TYPE_INVALID);
+ 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 (streq(state, "active") || streq(state, "reloading"))
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return strv_find(check_states, state) ? 1 : 0;
}
static void check_triggering_units(
DBusConnection *bus,
const char *unit_name) {
- DBusError error;
- DBusMessage *m = NULL, *reply = NULL;
+ _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";
-
- char *unit_path = NULL, *n = NULL;
+ *load_state_property = "LoadState",
+ *triggered_by_property = "TriggeredBy",
+ *state;
+ char _cleanup_free_ *unit_path = NULL, *n = NULL;
bool print_warning_label = true;
-
- dbus_error_init(&error);
+ int r;
n = unit_name_mangle(unit_name);
- unit_path = unit_dbus_path_from_name(n ? n : unit_name);
- free(n);
- if (!unit_path) {
- log_error("Could not allocate dbus path.");
- goto finish;
+ if (!n) {
+ log_oom();
+ return;
}
- m = dbus_message_new_method_call("org.freedesktop.systemd1",
- unit_path,
- "org.freedesktop.DBus.Properties",
- "Get");
- if (!m) {
- log_error("Could not allocate message.");
- goto finish;
+ unit_path = unit_dbus_path_from_name(n);
+ if (!unit_path) {
+ log_oom();
+ return;
}
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_STRING, &triggered_by_property,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- goto finish;
+ 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;
}
- 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));
- goto finish;
+ 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,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &triggered_by_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: %s", bus_error_message(&error));
- goto finish;
-
+ log_error("Failed to parse reply.");
+ return;
}
dbus_message_iter_recurse(&iter, &sub);
sub = iter;
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- int r;
+ 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: %s", bus_error_message(&error));
- goto finish;
+ log_error("Failed to parse reply.");
+ return;
}
dbus_message_iter_get_basic(&sub, &service_trigger);
- r = check_one_unit(bus, service_trigger, true);
+ r = check_one_unit(bus, service_trigger, (char**) check_states, true);
if (r < 0)
- goto finish;
- if (r == 0) {
+ return;
+ 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);
}
dbus_message_iter_next(&sub);
}
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- free(unit_path);
}
static int start_unit_one(
DBusError *error,
Set *s) {
- DBusMessage *m = NULL, *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ char *n;
const char *path;
int r;
- char *n;
- bool b;
- assert(bus);
assert(method);
assert(name);
assert(mode);
assert(error);
- assert(arg_no_block || s);
- m = dbus_message_new_method_call(
+ n = unit_name_mangle(name);
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
+ bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- method);
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- n = unit_name_mangle(name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? (const char **) &n : &name,
- DBUS_TYPE_STRING, &mode,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
- if (!reply) {
-
- if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
+ method,
+ &reply,
+ error,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+ if (r) {
+ if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
/* There's always a fallback possible for
* legacy actions. */
r = -EADDRNOTAVAIL;
- goto finish;
- }
+ else
+ log_error("Failed to issue method call: %s", bus_error_message(error));
- log_error("Failed to issue method call: %s", bus_error_message(error));
- r = -EIO;
- goto finish;
+ 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;
}
- if (need_daemon_reload(bus, name))
- log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
- arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
+ if (need_daemon_reload(bus, n))
+ log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
+ n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
- if (!arg_no_block) {
+ if (s) {
char *p;
- if (!(p = strdup(path))) {
- log_error("Failed to duplicate path.");
- r = -ENOMEM;
- goto finish;
- }
+ p = strdup(path);
+ if (!p)
+ return log_oom();
- if ((r = set_put(s, p)) < 0) {
+ r = set_put(s, p);
+ if (r < 0) {
free(p);
log_error("Failed to add path to set.");
- goto finish;
+ return r;
}
}
- /* When stopping a unit warn if it can still be triggered by
- * another active unit (socket, path, timer) */
- if (!arg_quiet && streq(method, "StopUnit"))
- check_triggering_units(bus, name);
-
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- return r;
+ 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
- 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
- };
-
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) {
- if ((ret = enable_wait_for_jobs(bus)) < 0) {
+ ret = enable_wait_for_jobs(bus);
+ if (ret < 0) {
log_error("Could not watch jobs: %s", strerror(-ret));
- goto finish;
+ return ret;
}
- if (!(s = set_new(string_hash_func, string_compare_func))) {
- log_error("Failed to allocate set.");
- ret = -ENOMEM;
- goto finish;
- }
+ s = set_new(string_hash_func, string_compare_func);
+ if (!s)
+ return log_oom();
}
if (one_name) {
- if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
- goto finish;
+ ret = start_unit_one(bus, method, one_name, mode, &error, s);
+ if (ret < 0)
+ ret = translate_bus_error_to_exit_status(ret, &error);
} else {
- STRV_FOREACH(name, args+1)
- if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
+ STRV_FOREACH(name, args+1) {
+ r = start_unit_one(bus, method, *name, mode, &error, s);
+ if (r < 0) {
ret = translate_bus_error_to_exit_status(r, &error);
dbus_error_free(&error);
}
- }
-
- if (!arg_no_block)
- if ((r = wait_for_jobs(bus, s)) < 0) {
- ret = r;
- goto finish;
}
+ }
-finish:
- if (s)
- set_free_free(s);
+ if (!arg_no_block) {
+ r = wait_for_jobs(bus, s);
+ if (r < 0)
+ return r;
- dbus_error_free(&error);
+ /* When stopping units, warn if they can still be triggered by
+ * another active unit (socket, path, timer) */
+ if (!arg_quiet && streq(method, "StopUnit")) {
+ if (one_name)
+ check_triggering_units(bus, one_name);
+ else
+ STRV_FOREACH(name, args+1)
+ check_triggering_units(bus, *name);
+ }
+ }
return ret;
}
static int reboot_with_logind(DBusConnection *bus, enum action a) {
#ifdef HAVE_LOGIND
const char *method;
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
dbus_bool_t interactive = true;
- int r;
- dbus_error_init(&error);
+ if (!bus)
+ return -EIO;
polkit_agent_open_if_enabled();
method = "Hibernate";
break;
+ case ACTION_HYBRID_SLEEP:
+ method = "HybridSleep";
+ break;
+
default:
return -EINVAL;
}
- m = dbus_message_new_method_call(
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- method);
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
+ return bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ method,
+ NULL,
+ NULL,
+ DBUS_TYPE_BOOLEAN, &interactive,
+ DBUS_TYPE_INVALID);
+#else
+ return -ENOSYS;
+#endif
+}
- if (!dbus_message_append_args(m,
- DBUS_TYPE_BOOLEAN, &interactive,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
+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;
- reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
- if (!reply) {
- if (error_is_no_service(&error)) {
- log_debug("Failed to issue method call: %s", bus_error_message(&error));
- r = -ENOENT;
- goto finish;
- }
+ if (!bus)
+ return 0;
- if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
- log_debug("Failed to issue method call: %s", bus_error_message(&error));
- r = -EACCES;
- goto finish;
- }
+ if (arg_ignore_inhibitors || arg_force > 0)
+ return 0;
- log_info("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
+ if (arg_when > 0)
+ return 0;
- r = 0;
+ if (geteuid() == 0)
+ return 0;
-finish:
- if (m)
- dbus_message_unref(m);
+ if (!on_tty())
+ return 0;
- if (reply)
- dbus_message_unref(reply);
+ 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;
- dbus_error_free(&error);
+ 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;
+ }
- return r;
-#else
- return -ENOSYS;
-#endif
-}
+ 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;
-static int start_special(DBusConnection *bus, char **args) {
- enum action a;
- int r;
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+ log_error("Failed to parse reply.");
+ return -EIO;
+ }
- assert(args);
+ dbus_message_iter_recurse(&sub, &sub2);
- a = verb_to_action(args[0]);
+ 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;
+
+ assert(args);
+
+ 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.");
(a == ACTION_POWEROFF ||
a == ACTION_REBOOT ||
a == ACTION_SUSPEND ||
- a == ACTION_HIBERNATE)) {
+ a == ACTION_HIBERNATE ||
+ a == ACTION_HYBRID_SLEEP)) {
r = reboot_with_logind(bus, a);
if (r >= 0)
return r;
}
r = start_unit(bus, args);
- if (r >= 0)
+ if (r == EXIT_SUCCESS)
warn_wall(a);
return r;
}
-static int check_unit(DBusConnection *bus, char **args) {
+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) {
- int state = check_one_unit(bus, *name, arg_quiet);
+ 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;
}
return r;
}
-static int kill_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL;
- int r = 0;
- DBusError error;
+static int check_unit_failed(DBusConnection *bus, char **args) {
+ const char * const check_states[] = {
+ "failed",
+ NULL
+ };
+
char **name;
+ int r = 1;
assert(bus);
assert(args);
- dbus_error_init(&error);
+ STRV_FOREACH(name, args+1) {
+ int state;
+
+ state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
+ if (state < 0)
+ return state;
+ if (state > 0)
+ r = 0;
+ }
+
+ return r;
+}
+
+static int kill_unit(DBusConnection *bus, char **args) {
+ char **name;
+ int r = 0;
+
+ assert(bus);
+ assert(args);
if (!arg_kill_who)
arg_kill_who = "all";
- if (!arg_kill_mode)
- arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
-
STRV_FOREACH(name, args+1) {
- DBusMessage *reply;
- char *n;
- bool b;
+ _cleanup_free_ char *n = NULL;
- m = dbus_message_new_method_call(
+ n = unit_name_mangle(*name);
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
+ bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "KillUnit");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
+ "KillUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_STRING, &arg_kill_who,
+ DBUS_TYPE_INT32, &arg_signal,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
+ }
+ return 0;
+}
- n = unit_name_mangle(*name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? &n : name,
- DBUS_TYPE_STRING, &arg_kill_who,
- DBUS_TYPE_STRING, &arg_kill_mode,
- DBUS_TYPE_INT32, &arg_signal,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
+static int set_cgroup(DBusConnection *bus, char **args) {
+ _cleanup_free_ char *n = NULL;
+ const char *method, *runtime;
+ char **argument;
+ int r;
- 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);
- r = -EIO;
- }
+ assert(bus);
+ assert(args);
- dbus_message_unref(m);
+ method =
+ streq(args[0], "set-cgroup") ? "SetUnitControlGroup" :
+ streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
+ : "UnsetUnitControlGroupAttribute";
- if (reply)
- dbus_message_unref(reply);
- m = reply = NULL;
+ 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;
}
-finish:
- if (m)
- dbus_message_unref(m);
+ return 0;
+}
- dbus_error_free(&error);
+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;
- return 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;
}
typedef struct ExecStatusInfo {
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) ||
ExecStatusInfo *p;
const char *on, *off, *ss;
usec_t timestamp;
- char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+ 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);
streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
i->active_exit_timestamp;
- s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
+ s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
s2 = format_timestamp(since2, sizeof(since2), timestamp);
if (s1)
printf("\n");
if (!i->condition_result && i->condition_timestamp > 0) {
- s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
+ s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
if (s1)
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);
+ good = is_clean_exit_lsb(p->code, p->status, NULL);
if (!good) {
on = ansi_highlight_red(true);
off = ansi_highlight_red(false);
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->status_text)
printf("\t Status: \"%s\"\n", i->status_text);
- if (i->default_control_group) {
+ if (i->default_control_group &&
+ (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
unsigned c;
printf("\t CGroup: %s\n", i->default_control_group);
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) {
printf("\n");
- show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow, !arg_quiet);
+ 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_error("Out of memory.");
- return;
- }
-
section = strndup(e + 1, *p + k - e - 2);
- if (!section) {
- free(page);
- log_error("Out of memory");
+ 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);
+ 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 *m = NULL, *reply = NULL;
+ _cleanup_free_ DBusMessage *reply = NULL;
const char *interface = "";
int r;
- DBusError error;
DBusMessageIter iter, sub, sub2, sub3;
UnitStatusInfo info;
ExecStatusInfo *p;
- assert(bus);
assert(path);
assert(new_line);
zero(info);
- dbus_error_init(&error);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.DBus.Properties",
- "GetAll"))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
+ 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.");
- 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) {
+ 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;
- }
-
- if (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 (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
return r;
}
static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
- DBusMessage *m = NULL, *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);
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnitByPID");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &pid,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- 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;
- }
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnitByPID",
+ &reply,
+ NULL,
+ DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_INVALID);
+ 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 (m)
- dbus_message_unref(m);
+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;
- if (reply)
- dbus_message_unref(reply);
+ r = get_unit_list(bus, &reply, &unit_infos, &c);
+ if (r < 0)
+ return r;
- dbus_error_free(&error);
+ for (u = unit_infos; u < unit_infos + c; u++) {
+ char _cleanup_free_ *p = NULL;
- return r;
+ 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 (!p) {
- log_error("Out of memory");
- return -ENOMEM;
- }
+ if (!n)
+ return log_oom();
- r = show_one(args[0], bus, p, show_properties, &new_line);
- free(p);
+ p = unit_dbus_path_from_name(n);
+ if (!p)
+ return log_oom();
+ r = show_one(args[0], bus, p, show_properties, &new_line);
if (r != 0)
ret = r;
} 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) {
- log_error("Out of memory");
- return -ENOMEM;
- }
+ 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 *m = NULL, *reply = NULL;
+ _cleanup_free_ DBusMessage *reply = NULL;
DBusError error;
int r;
const char *text;
pager_open_if_enabled();
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Dump"))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Dump",
+ &reply,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
+ dbus_error_free(&error);
+ return -EIO;
}
fputs(text, stdout);
-
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int snapshot(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusError error;
int r;
- const char *name = "", *path, *id;
dbus_bool_t cleanup = FALSE;
DBusMessageIter iter, sub;
const char
+ *path, *id,
*interface = "org.freedesktop.systemd1.Unit",
*property = "Id";
- char *n;
- bool b;
+ _cleanup_free_ char *n = NULL;
dbus_error_init(&error);
- m = dbus_message_new_method_call(
+ if (strv_length(args) > 1)
+ n = snapshot_name_mangle(args[1]);
+ else
+ n = strdup("");
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply (
+ bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "CreateSnapshot");
- if (!m) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (strv_length(args) > 1)
- name = args[1];
-
- n = unit_name_mangle(name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? (const char**) &n : &name,
- DBUS_TYPE_BOOLEAN, &cleanup,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- 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;
- }
+ "CreateSnapshot",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_BOOLEAN, &cleanup,
+ DBUS_TYPE_INVALID);
+ 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_message_unref(m);
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.DBus.Properties",
- "Get");
- if (!m) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_STRING, &property,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
+ dbus_error_free(&error);
+ return -EIO;
}
dbus_message_unref(reply);
- 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;
- }
+ reply = NULL;
+
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &property,
+ DBUS_TYPE_INVALID);
+ 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);
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int delete_snapshot(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- int r;
- DBusError error;
char **name;
- assert(bus);
assert(args);
- dbus_error_init(&error);
-
STRV_FOREACH(name, args+1) {
- const char *path = NULL;
- char *n;
- bool b;
+ _cleanup_free_ char *n = NULL;
+ int r;
- m = dbus_message_new_method_call(
+ 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");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- n = unit_name_mangle(*name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? &n : name,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- 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;
- }
-
- 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_message_unref(m);
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.systemd1.Snapshot",
- "Remove");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- dbus_message_unref(reply);
- 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_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
+ "RemoveSnapshot",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
}
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int daemon_reload(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
int r;
const char *method;
-
- dbus_error_init(&error);
+ DBusError error;
if (arg_action == ACTION_RELOAD)
method = "Reload";
/* "daemon-reload" */ "Reload";
}
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-
- if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
- /* There's always a fallback possible for
- * legacy actions. */
- r = -EADDRNOTAVAIL;
- goto finish;
- }
-
- if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
- /* On reexecution, we expect a disconnect, not
- * a reply */
- r = 0;
- goto finish;
- }
-
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method,
+ NULL,
+ &error,
+ DBUS_TYPE_INVALID);
+
+ if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
+ /* There's always a fallback possible for
+ * legacy actions. */
+ r = -EADDRNOTAVAIL;
+ else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
+ /* On reexecution, we expect a disconnect, not
+ * a reply */
+ r = 0;
+ else if (r < 0)
log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
-
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
-}
-
-static int reset_failed(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL;
- int r;
- DBusError error;
- char **name;
-
- assert(bus);
- dbus_error_init(&error);
-
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
-
- STRV_FOREACH(name, args+1) {
- DBusMessage *reply;
- char *n;
- bool b;
-
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ResetFailedUnit");
- if (!m) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- n = unit_name_mangle(*name);
- b = dbus_message_append_args(m,
- DBUS_TYPE_STRING, n ? &n : name,
- DBUS_TYPE_INVALID);
- free(n);
- if (!b) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- 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_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
- }
+ dbus_error_free(&error);
+ return r;
+}
- r = 0;
+static int reset_failed(DBusConnection *bus, char **args) {
+ int r = 0;
+ char **name;
-finish:
- if (m)
- dbus_message_unref(m);
+ if (strv_length(args) <= 1)
+ return daemon_reload(bus, args);
- dbus_error_free(&error);
+ STRV_FOREACH(name, args+1) {
+ _cleanup_free_ char *n;
- return r;
+ n = unit_name_mangle(*name);
+ if (!n)
+ return log_oom();
+
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ResetFailedUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, &n,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
}
static int show_enviroment(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
DBusMessageIter iter, sub, sub2;
int r;
const char
*interface = "org.freedesktop.systemd1.Manager",
*property = "Environment";
- dbus_error_init(&error);
-
pager_open_if_enabled();
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.DBus.Properties",
- "Get"))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &interface,
- DBUS_TYPE_STRING, &property,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
- }
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &property,
+ DBUS_TYPE_INVALID);
+ 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 (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int switch_root(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
unsigned l;
- const char *root, *init;
- DBusError error;
- int r;
-
- dbus_error_init(&error);
+ const char *root;
+ _cleanup_free_ char *init = NULL;
l = strv_length(args);
if (l < 2 || l > 3) {
}
root = args[1];
- init = l >= 3 ? args[2] : "";
-
- m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SwitchRoot");
- if (!m) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
- if (!dbus_message_append_args(
- m,
- DBUS_TYPE_STRING, &root,
- DBUS_TYPE_STRING, &init,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
+ if (l >= 3)
+ init = strdup(args[2]);
+ else {
+ parse_env_file("/proc/cmdline", WHITESPACE,
+ "init", &init,
+ NULL);
- 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;
+ if (!init)
+ init = strdup("");
}
+ if (!init)
+ return log_oom();
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
+ log_debug("switching root - root: %s; init: %s", root, init);
- return r;
+ return bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SwitchRoot",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, &root,
+ DBUS_TYPE_STRING, &init,
+ DBUS_TYPE_INVALID);
}
static int set_environment(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
DBusError error;
- int r;
const char *method;
- DBusMessageIter iter, sub;
- char **name;
+ DBusMessageIter iter;
+ int r;
+
+ assert(bus);
+ assert(args);
dbus_error_init(&error);
? "SetEnvironment"
: "UnsetEnvironment";
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method))) {
-
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
+ m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method);
+ if (!m)
+ return log_oom();
dbus_message_iter_init_append(m, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- STRV_FOREACH(name, args+1)
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
+ r = bus_append_strv_iter(&iter, args + 1);
+ if (r < 0)
+ return log_oom();
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &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:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
static int enable_sysv_units(char **args) {
int r = 0;
-#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
+#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
const char *verb = args[0];
unsigned f = 1, t = 1;
LookupPaths paths;
* afterwards only the native units remain */
zero(paths);
- r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
+ r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
if (r < 0)
return r;
asprintf(&p, "%s/%s", *k, name);
if (!p) {
- log_error("No memory");
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
else
asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
if (!p) {
- log_error("No memory");
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
l = strv_join((char**)argv, " ");
if (!l) {
- log_error("No memory.");
free(q);
free(p);
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
return r;
}
+static int mangle_names(char **original_names, char ***mangled_names) {
+ char **i, **l, **name;
+
+ l = new(char*, strv_length(original_names) + 1);
+ if (!l)
+ return log_oom();
+
+ i = l;
+ STRV_FOREACH(name, original_names) {
+
+ /* When enabling units qualified path names are OK,
+ * too, hence allow them explicitly. */
+
+ if (is_path(*name))
+ *i = strdup(*name);
+ else
+ *i = unit_name_mangle(*name);
+
+ if (!*i) {
+ strv_free(l);
+ return log_oom();
+ }
+
+ i++;
+ }
+
+ *i = NULL;
+ *mangled_names = l;
+
+ return 0;
+}
+
static int enable_unit(DBusConnection *bus, char **args) {
const char *verb = args[0];
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;
+ 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);
}
}
+ r = 0;
} else {
const char *method;
bool send_force = true, expect_carries_install_info = false;
"org.freedesktop.systemd1.Manager",
method);
if (!m) {
- log_error("Out of memory");
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
dbus_message_iter_init_append(m, &iter);
- r = bus_append_strv_iter(&iter, args+1);
+ r = mangle_names(args+1, &mangled_names);
+ if(r < 0)
+ goto finish;
+
+ r = bus_append_strv_iter(&iter, mangled_names);
if (r < 0) {
log_error("Failed to append unit files.");
goto finish;
}
if (carries_install_info == 0)
- log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
+ 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);
return r;
}
static int unit_is_enabled(DBusConnection *bus, char **args) {
- DBusError error;
+ DBusError _cleanup_dbus_error_free_ error;
int r;
- DBusMessage *m = NULL, *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 ||
STRV_FOREACH(name, args+1) {
const char *s;
- m = dbus_message_new_method_call(
+ r = bus_method_call_with_reply (
+ bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "GetUnitFileState");
- if (!m) {
- log_error("Out of memory");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, name,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- 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;
- }
+ "GetUnitFileState",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, name,
+ DBUS_TYPE_INVALID);
+ if (r)
+ 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(m);
dbus_message_unref(reply);
- m = reply = NULL;
+ reply = NULL;
if (streq(s, "enabled") ||
streq(s, "enabled-runtime") ||
}
}
- r = enabled ? 0 : 1;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- 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"
" --root=PATH Enable unit files in the specified root directory\n"
" --runtime Enable unit files only temporarily until next reboot\n"
" -n --lines=INTEGER Journal entries to show\n"
- " --follow Follow journal\n"
" -o --output=STRING Change journal output mode (short, short-monotonic,\n"
- " verbose, export, json, cat)\n\n"
+ " verbose, export, json, json-pretty, json-sse, cat)\n\n"
"Unit Commands:\n"
" list-units List loaded units\n"
" start [NAME...] Start (activate) one or more units\n"
" reload [NAME...] Reload one or more units\n"
" restart [NAME...] Start or restart one or more units\n"
" try-restart [NAME...] Restart one or more units if active\n"
- " reload-or-restart [NAME...] Reload one or more units is possible,\n"
+ " reload-or-restart [NAME...] Reload one or more units if possible,\n"
" otherwise start or restart\n"
- " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
+ " reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
" otherwise restart if active\n"
" isolate [NAME] Start one unit and stop all others\n"
" kill [NAME...] Send signal to processes of a unit\n"
" is-active [NAME...] Check whether units are active\n"
+ " is-failed [NAME...] Check whether units are failed\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"
" exit Request user instance exit\n"
" switch-root [ROOT] [INIT] Change to a different root file system\n"
" suspend Suspend the system\n"
- " hibernate Hibernate the system\n",
+ " hibernate Hibernate the system\n"
+ " hybrid-sleep Hibernate and suspend the system\n",
program_invocation_short_name);
return 0;
" -f --force Force immediate halt/power-off/reboot\n"
" -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
" -d --no-wtmp Don't write wtmp record\n"
- " -n --no-sync Don't sync before halt/power-off/reboot\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n",
program_invocation_short_name,
arg_action == ACTION_REBOOT ? "Reboot" :
return 0;
}
+static int help_types(void) {
+ int i;
+
+ puts("Available unit types:");
+ for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++)
+ if (unit_type_table[i])
+ puts(unit_type_table[i]);
+
+ puts("\nAvailable unit load states: ");
+ for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++)
+ if (unit_type_table[i])
+ puts(unit_load_state_table[i]);
+
+ return 0;
+}
+
static int systemctl_parse_argv(int argc, char *argv[]) {
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,
- ARG_KILL_MODE,
ARG_KILL_WHO,
ARG_NO_ASK_PASSWORD,
ARG_FAILED,
ARG_RUNTIME,
- ARG_FOLLOW,
ARG_FORCE
};
{ "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 },
- { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
{ "signal", required_argument, NULL, 's' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "privileged",no_argument, NULL, 'P' },
{ "runtime", no_argument, NULL, ARG_RUNTIME },
{ "lines", required_argument, NULL, 'n' },
- { "follow", no_argument, NULL, ARG_FOLLOW },
{ "output", required_argument, NULL, 'o' },
{ NULL, 0, NULL, 0 }
};
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;
case 't':
- arg_type = optarg;
- break;
+ if (streq(optarg, "help")) {
+ help_types();
+ return 0;
+ }
+ if (unit_type_from_string(optarg) >= 0) {
+ arg_type = optarg;
+ break;
+ }
+ if (unit_load_state_from_string(optarg) >= 0) {
+ arg_load_state = optarg;
+ break;
+ }
+ log_error("Unkown unit type or load state '%s'.",
+ optarg);
+ 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;
arg_force ++;
break;
- case ARG_FOLLOW:
- arg_follow = true;
- break;
-
case 'f':
- /* -f is short for both --follow and --force! */
arg_force ++;
- arg_follow = true;
break;
case ARG_NO_RELOAD:
arg_kill_who = optarg;
break;
- case ARG_KILL_MODE:
- arg_kill_mode = optarg;
- break;
-
case 's':
if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
log_error("Failed to parse signal string %s.", optarg);
}
break;
+ case 'i':
+ arg_ignore_inhibitors = true;
+ break;
+
case '?':
return -EINVAL;
{ "force", no_argument, NULL, 'f' },
{ "wtmp-only", no_argument, NULL, 'w' },
{ "no-wtmp", no_argument, NULL, 'd' },
- { "no-sync", no_argument, NULL, 'n' },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{ NULL, 0, NULL, 0 }
};
arg_no_wtmp = true;
break;
- case 'n':
- arg_no_sync = true;
- break;
-
case ARG_NO_WALL:
arg_no_wall = true;
break;
case 'i':
case 'h':
+ case 'n':
/* Compatibility nops */
break;
}
}
- if (argc > optind) {
+ if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
r = parse_time_spec(argv[optind], &arg_when);
if (r < 0) {
log_error("Failed to parse time specification: %s", argv[optind]);
} else
arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
- /* We skip the time argument */
- if (argc > optind + 1)
+ if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
+ /* No time argument for shutdown cancel */
+ arg_wall = argv + optind;
+ else if (argc > optind + 1)
+ /* We skip the time argument */
arg_wall = argv + optind + 1;
optind = argc;
}
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",
if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
- if (error_is_no_service(&error)) {
+ if (bus_error_is_no_service(&error)) {
r = -EADDRNOTAVAIL;
goto finish;
}
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 },
- { "check", MORE, 2, check_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 },
{ "kexec", EQUAL, 1, start_special },
{ "suspend", EQUAL, 1, start_special },
{ "hibernate", EQUAL, 1, start_special },
+ { "hybrid-sleep", EQUAL, 1, start_special },
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special },
{ "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;
}
return 0;
}
-static void halt_now(enum action a) {
+static _noreturn_ void halt_now(enum action a) {
/* Make sure C-A-D is handled by the kernel from this
* point on... */
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));
}
}
- if (!arg_no_sync)
- sync();
-
if (arg_dry)
return 0;
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);
+ setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = reload_with_fallback(bus);
break;
- case ACTION_CANCEL_SHUTDOWN:
- r = send_shutdownd(0, 0, false, false, NULL);
+ case ACTION_CANCEL_SHUTDOWN: {
+ char *m = NULL;
+
+ if (arg_wall) {
+ m = strv_join(arg_wall, " ");
+ if (!m) {
+ retval = EXIT_FAILURE;
+ goto finish;
+ }
+ }
+ r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
+ if (r < 0)
+ log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
+ free(m);
break;
+ }
case ACTION_INVALID:
case ACTION_RUNLEVEL:
dbus_connection_unref(bus);
}
- dbus_error_free(&error);
-
dbus_shutdown();
strv_free(arg_property);