#include <sys/reboot.h>
#include <stdio.h>
#include <getopt.h>
+#include <locale.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include "utmp-wtmp.h"
#include "special.h"
#include "initreq.h"
+#include "path-util.h"
#include "strv.h"
#include "dbus-common.h"
#include "cgroup-show.h"
#include "spawn-polkit-agent.h"
#include "install.h"
#include "logs-show.h"
+#include "path-util.h"
+#include "socket-util.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 UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
-static bool arg_immediate = false;
static bool arg_no_block = false;
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_dry = 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_REBOOT,
ACTION_KEXEC,
ACTION_EXIT,
+ ACTION_SUSPEND,
+ ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP,
ACTION_RUNLEVEL2,
ACTION_RUNLEVEL3,
ACTION_RUNLEVEL4,
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;
ask_password_agent_open();
}
+#ifdef HAVE_LOGIND
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
polkit_agent_open();
}
+#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 (!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;
const char *on_loaded, *off_loaded;
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
}
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;
+ DBusMessage *reply = NULL;
int r;
DBusMessageIter iter, sub, sub2;
unsigned c = 0, n_units = 0;
struct unit_info *unit_infos = NULL;
- dbus_error_init(&error);
-
- assert(bus);
-
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;
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnits",
+ &reply,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
output_units_list(unit_infos, c);
}
- r = 0;
-
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
free(unit_infos);
- dbus_error_free(&error);
-
return r;
}
return r;
}
- return strcasecmp(file_name_from_path(u->path), file_name_from_path(v->path));
+ return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
}
static bool output_show_unit_file(const UnitFileList *u) {
if (!output_show_unit_file(u))
continue;
- max_id_len = MAX(max_id_len, strlen(file_name_from_path(u->path)));
+ max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
}
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) {
} else
on = off = "";
- id = file_name_from_path(u->path);
+ id = path_get_file_name(u->path);
e = arg_full ? NULL : ellipsize(id, id_cols, 33);
}
static int list_unit_files(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+ DBusMessage *reply = NULL;
int r;
DBusMessageIter iter, sub, sub2;
unsigned c = 0, n_units = 0;
UnitFileList *units = NULL;
- dbus_error_init(&error);
-
pager_open_if_enabled();
if (avoid_bus()) {
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;
+ "ListUnitFiles",
+ &reply,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
free(units);
- dbus_error_free(&error);
-
return r;
}
"RequiresOverridable", "[color=\"black\"]",
"Requisite", "[color=\"darkblue\"]",
"RequisiteOverridable", "[color=\"darkblue\"]",
- "Wants", "[color=\"darkgrey\"]",
+ "Wants", "[color=\"grey66\"]",
"Conflicts", "[color=\"red\"]",
"ConflictedBy", "[color=\"red\"]",
"After", "[color=\"green\"]"
}
static int dot_one(DBusConnection *bus, const char *name, const char *path) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *reply = NULL;
const char *interface = "org.freedesktop.systemd1.Unit";
int r;
- DBusError error;
DBusMessageIter iter, sub, sub2, sub3;
- assert(bus);
assert(path);
- 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;
+ 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)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
dbus_message_iter_next(&sub);
}
- r = 0;
-
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
- dbus_error_free(&error);
-
return r;
}
static int dot(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+ DBusMessage *reply = NULL;
int r;
DBusMessageIter iter, sub, sub2;
- dbus_error_init(&error);
-
- assert(bus);
-
- 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;
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnits",
+ &reply,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
- dbus_error_free(&error);
-
return r;
}
static int list_jobs(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+ DBusMessage *reply = NULL;
int r;
DBusMessageIter iter, sub, sub2;
unsigned k = 0;
- dbus_error_init(&error);
-
- assert(bus);
-
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;
+ 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)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
- dbus_error_free(&error);
-
return r;
}
static int load_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL;
- DBusError error;
- int r;
- char **name;
-
- dbus_error_init(&error);
+ int r = 0;
+ char **name, *n;
- assert(bus);
assert(args);
STRV_FOREACH(name, args+1) {
- DBusMessage *reply;
-
- 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;
- }
-
- 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;
- }
-
- 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;
+ n = unit_name_mangle(*name);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LoadUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r)
goto finish;
- }
-
- dbus_message_unref(m);
- dbus_message_unref(reply);
-
- m = reply = NULL;
}
- r = 0;
-
finish:
- if (m)
- dbus_message_unref(m);
-
- dbus_error_free(&error);
-
return r;
}
static int cancel_job(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
- int r;
+ DBusMessage *reply = NULL;
+ int r = 0;
char **name;
- dbus_error_init(&error);
-
- assert(bus);
assert(args);
if (strv_length(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;
- }
-
- if ((r = safe_atou(*name, &id)) < 0) {
+ r = safe_atou(*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;
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetJob",
+ &reply,
+ NULL,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_INVALID);
+ if (r)
goto finish;
- }
- if (!dbus_message_get_args(reply, &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));
+ log_error("Failed to parse reply");
+ dbus_message_unref(reply);
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;
- }
- dbus_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Job",
+ "Cancel",
+ NULL,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r)
+ goto finish;
}
- r = 0;
-
finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
return r;
}
static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *reply = NULL;
dbus_bool_t b = FALSE;
DBusMessageIter iter, sub;
const char
*interface = "org.freedesktop.systemd1.Unit",
*property = "NeedDaemonReload",
*path;
+ char *n;
+ int r;
/* We ignore all errors here, since this is used to show a warning only */
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit")))
- goto finish;
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &unit,
- DBUS_TYPE_INVALID))
- goto finish;
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
+ n = unit_name_mangle(unit);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r)
goto finish;
if (!dbus_message_get_args(reply, NULL,
DBUS_TYPE_INVALID))
goto finish;
- dbus_message_unref(m);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.DBus.Properties",
- "Get")))
- 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);
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, 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)
goto finish;
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_basic(&sub, &b);
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
typedef struct WaitData {
Set *set;
+
+ char *name;
char *result;
} WaitData;
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path, *result;
+ const char *path, *result, *unit;
dbus_bool_t success = true;
if (dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &unit,
DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID)) {
char *p;
- if ((p = set_remove(d->set, (char*) path)))
- free(p);
+ p = set_remove(d->set, (char*) path);
+ free(p);
- if (*result)
+ if (!isempty(result))
d->result = strdup(result);
+ if (!isempty(unit))
+ d->name = strdup(unit);
+
goto finish;
}
#ifndef LEGACY
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_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);
+
+ 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;
* 19 during upgrades. This should be dropped
* one day */
- if ((p = set_remove(d->set, (char*) path)))
- free(p);
+ p = set_remove(d->set, (char*) path);
+ free(p);
if (!success)
d->result = strdup("failed");
}
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;
+ if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
+ return log_oom();
+
+ while (!set_isempty(s)) {
+
+ if (!dbus_connection_read_write_dispatch(bus, -1)) {
+ log_error("Disconnected from bus.");
+ return -ECONNREFUSED;
+ }
+
+ if (!d.result)
+ goto free_name;
+
+ 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));
+ }
+
+ 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 *reply = NULL;
+ DBusMessageIter iter, sub;
+ const char
+ *interface = "org.freedesktop.systemd1.Unit",
+ *property = "ActiveState";
+ const char *path = NULL;
+ const char *state;
+ int r;
+ char *n;
+
+ assert(name);
+
+ n = unit_name_mangle(name);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, n ? &n : &name,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r) {
+ if ((r != -ENOMEM) && (!quiet))
+ puts("unknown");
goto finish;
}
- while (!set_isempty(s) &&
- dbus_connection_read_write_dispatch(bus, -1))
- ;
+ if (!dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID)) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
- 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.");
+ dbus_message_unref(reply);
+ 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)
+ goto finish;
+
+ 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;
}
- 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"))
+ 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;
- else
- r = 0;
+ goto finish;
+ }
- free(d.result);
+ dbus_message_iter_get_basic(&sub, &state);
+
+ if (!quiet)
+ puts(state);
+
+ if (streq(state, "active") || streq(state, "reloading"))
+ r = 0;
+ else
+ r = 3; /* According to LSB: "program is not running" */
finish:
- /* This is slightly dirty, since we don't undo the filter registration. */
+ if (reply)
+ dbus_message_unref(reply);
return r;
}
+static void check_triggering_units(
+ DBusConnection *bus,
+ const char *unit_name) {
+
+ _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 _cleanup_free_ *unit_path = NULL, *n = NULL;
+ bool print_warning_label = true;
+ int r;
+
+ n = unit_name_mangle(unit_name);
+ if (!n) {
+ log_oom();
+ return;
+ }
+
+ unit_path = unit_dbus_path_from_name(n);
+ if (!unit_path) {
+ log_oom();
+ return;
+ }
+
+ 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)
+ return;
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+ log_error("Failed to parse reply.");
+ return;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+ dbus_message_iter_recurse(&sub, &iter);
+ sub = iter;
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+ log_error("Failed to parse reply.");
+ return;
+ }
+
+ dbus_message_iter_get_basic(&sub, &service_trigger);
+
+ r = check_one_unit(bus, service_trigger, true);
+ 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);
+ }
+}
+
static int start_unit_one(
DBusConnection *bus,
const char *method,
DBusError *error,
Set *s) {
- DBusMessage *m = NULL, *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
const char *path;
int r;
+ _cleanup_free_ char *n, *p = NULL;
- assert(bus);
assert(method);
assert(name);
assert(mode);
assert(error);
- assert(arg_no_block || s);
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &mode,
- 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))) {
-
- if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
+ 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,
+ &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) {
- char *p;
-
- if (!(p = strdup(path))) {
- log_error("Failed to duplicate path.");
- r = -ENOMEM;
- goto finish;
- }
+ if (s) {
+ p = strdup(path);
+ if (!p)
+ return log_oom();
- if ((r = set_put(s, p)) < 0) {
- free(p);
+ r = set_put(s, p);
+ if (r < 0) {
log_error("Failed to add path to set.");
- goto finish;
+ return r;
}
- }
-
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
- if (reply)
- dbus_message_unref(reply);
+ p = NULL;
+ }
- return r;
+ return 0;
}
static enum action verb_to_action(const char *verb) {
return ACTION_DEFAULT;
else if (streq(verb, "exit"))
return ACTION_EXIT;
+ else if (streq(verb, "suspend"))
+ return ACTION_SUSPEND;
+ else if (streq(verb, "hibernate"))
+ return ACTION_HIBERNATE;
+ else if (streq(verb, "hybrid-sleep"))
+ return ACTION_HYBRID_SLEEP;
else
return ACTION_INVALID;
}
[ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
[ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
[ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
- [ACTION_EXIT] = SPECIAL_EXIT_TARGET
+ [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
+ [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
+ [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
+ [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
};
int r, ret = 0;
}
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;
}
- if (!(s = set_new(string_hash_func, string_compare_func))) {
- log_error("Failed to allocate set.");
- ret = -ENOMEM;
+ s = set_new(string_hash_func, string_compare_func);
+ if (!s) {
+ ret = log_oom();
goto finish;
}
}
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) {
+ if (!arg_no_block) {
+ r = wait_for_jobs(bus, s);
+ if (r < 0) {
ret = r;
goto finish;
}
-finish:
- if (s)
- set_free_free(s);
+ /* 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);
+ }
+ }
+finish:
+ set_free_free(s);
dbus_error_free(&error);
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);
polkit_agent_open_if_enabled();
method = "PowerOff";
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;
- }
-
- 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;
- }
+ case ACTION_SUSPEND:
+ method = "Suspend";
+ break;
- 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;
- }
+ case ACTION_HIBERNATE:
+ method = "Hibernate";
+ break;
- 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;
- }
+ case ACTION_HYBRID_SLEEP:
+ method = "HybridSleep";
+ break;
- log_info("Failed to issue method call: %s", bus_error_message(&error));
- r = -EIO;
- goto finish;
+ default:
+ return -EINVAL;
}
- r = 0;
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return r;
+ 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
enum action a;
int r;
- assert(bus);
assert(args);
a = verb_to_action(args[0]);
+ if (arg_force >= 2 && geteuid() != 0) {
+ log_error("Must be root.");
+ return -EPERM;
+ }
+
if (arg_force >= 2 &&
(a == ACTION_HALT ||
a == ACTION_POWEROFF ||
/* first try logind, to allow authentication with polkit */
if (geteuid() != 0 &&
(a == ACTION_POWEROFF ||
- a == ACTION_REBOOT)) {
+ a == ACTION_REBOOT ||
+ a == ACTION_SUSPEND ||
+ a == ACTION_HIBERNATE ||
+ a == ACTION_HYBRID_SLEEP)) {
r = reboot_with_logind(bus, a);
if (r >= 0)
return r;
}
static int check_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- const char
- *interface = "org.freedesktop.systemd1.Unit",
- *property = "ActiveState";
- int r = 3; /* According to LSB: "program is not running" */
- DBusError error;
char **name;
+ int r = 3; /* According to LSB: "program is not running" */
assert(bus);
assert(args);
- dbus_error_init(&error);
-
- STRV_FOREACH(name, args+1) {
- const char *path = NULL;
- const char *state;
- DBusMessageIter iter, sub;
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit"))) {
- log_error("Could not allocate message.");
- 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;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-
- /* Hmm, cannot figure out anything about this unit... */
- if (!arg_quiet)
- puts("unknown");
-
- dbus_error_free(&error);
- dbus_message_unref(m);
- m = NULL;
- continue;
- }
-
- 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.DBus.Properties",
- "Get"))) {
- 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;
- }
-
- 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;
- }
-
- 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;
- }
-
- 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;
- }
-
- dbus_message_iter_get_basic(&sub, &state);
-
- if (!arg_quiet)
- puts(state);
-
- if (streq(state, "active") || streq(state, "reloading"))
- r = 0;
-
- dbus_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
- }
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
+ STRV_FOREACH(name, args+1) {
+ int state = check_one_unit(bus, *name, arg_quiet);
+ if (state < 0)
+ return state;
+ if (state == 0)
+ r = 0;
+ }
return r;
}
static int kill_unit(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL;
int r = 0;
- DBusError error;
- char **name;
+ char **name, *n;
- assert(bus);
assert(args);
- dbus_error_init(&error);
-
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;
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "KillUnit"))) {
- log_error("Could not allocate message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, name,
- DBUS_TYPE_STRING, &arg_kill_who,
- DBUS_TYPE_STRING, &arg_kill_mode,
- DBUS_TYPE_INT32, &arg_signal,
- 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));
- dbus_error_free(&error);
- r = -EIO;
- }
-
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
- m = reply = NULL;
+ n = unit_name_mangle(*name);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "KillUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_STRING, &arg_kill_who,
+ DBUS_TYPE_INT32, &arg_signal,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r)
+ return r;
}
-
-finish:
- if (m)
- dbus_message_unref(m);
-
- dbus_error_free(&error);
-
- return r;
+ return 0;
}
typedef struct ExecStatusInfo {
const char *description;
const char *following;
- const char *path;
+ char **documentation;
+
+ const char *fragment_path;
+ const char *source_path;
const char *default_control_group;
const char *load_error;
pid_t control_pid;
const char *status_text;
bool running:1;
-#ifdef HAVE_SYSV_COMPAT
- bool is_sysv:1;
-#endif
usec_t start_timestamp;
usec_t exit_timestamp;
usec_t timestamp;
char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
char since2[FORMAT_TIMESTAMP_MAX], *s2;
+ const char *path;
assert(i);
} else
on = off = "";
+ path = i->source_path ? i->source_path : i->fragment_path;
+
if (i->load_error)
printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
- else if (i->path && i->unit_file_state)
- printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state);
- else if (i->path)
- printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
+ else if (path && i->unit_file_state)
+ printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
+ else if (path)
+ printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
else
printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off);
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)
if (i->what)
printf("\t What: %s\n", i->what);
+ if (!strv_isempty(i->documentation)) {
+ char **t;
+ bool first = true;
+
+ STRV_FOREACH(t, i->documentation) {
+ if (first) {
+ printf("\t Docs: %s\n", *t);
+ first = false;
+ } else
+ printf("\t %s\n", *t);
+ }
+ }
+
if (i->accept)
printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
free(t);
-#ifdef HAVE_SYSV_COMPAT
- if (i->is_sysv)
- good = is_clean_exit_lsb(p->code, p->status);
- else
-#endif
- good = is_clean_exit(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("status=%i", p->status);
-#ifdef HAVE_SYSV_COMPAT
- if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
-#else
- if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
-#endif
+ c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
+ if (c)
printf("/%s", c);
} else
printf("status=%i", i->exit_status);
-#ifdef HAVE_SYSV_COMPAT
- if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
-#else
- if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
-#endif
+ c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
+ if (c)
printf("/%s", c);
} else
printf("\t CGroup: %s\n", i->default_control_group);
if (arg_transport != TRANSPORT_SSH) {
- if ((c = columns()) > 18)
+ unsigned k = 0;
+ pid_t extra[2];
+
+ c = columns();
+ if (c > 18)
c -= 18;
else
c = 0;
- show_cgroup_by_path(i->default_control_group, "\t\t ", c, false, arg_all);
+ if (i->main_pid > 0)
+ extra[k++] = i->main_pid;
+
+ 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);
}
}
if (i->id && arg_transport != TRANSPORT_SSH) {
+ int flags =
+ arg_all * OUTPUT_SHOW_ALL |
+ (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
+ on_tty() * OUTPUT_COLOR |
+ !arg_quiet * OUTPUT_WARN_CUTOFF;
+
printf("\n");
- show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
+ show_journal_by_unit(stdout,
+ i->id,
+ arg_output,
+ 0,
+ i->inactive_exit_timestamp_monotonic,
+ arg_lines,
+ flags);
}
if (i->need_daemon_reload)
arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
}
+static void show_unit_help(UnitStatusInfo *i) {
+ char **p;
+
+ assert(i);
+
+ if (!i->documentation) {
+ log_info("Documentation for %s not known.", i->id);
+ return;
+ }
+
+ STRV_FOREACH(p, i->documentation) {
+
+ if (startswith(*p, "man:")) {
+ size_t k;
+ char *e = NULL;
+ char *page = NULL, *section = NULL;
+ const char *args[4] = { "man", NULL, NULL, NULL };
+ pid_t pid;
+
+ k = strlen(*p);
+
+ if ((*p)[k-1] == ')')
+ e = strrchr(*p, '(');
+
+ if (e) {
+ page = strndup((*p) + 4, e - *p - 4);
+ if (!page) {
+ log_oom();
+ return;
+ }
+
+ section = strndup(e + 1, *p + k - e - 2);
+ if (!section) {
+ free(page);
+ log_oom();
+ return;
+ }
+
+ args[1] = section;
+ args[2] = page;
+ } else
+ args[1] = *p + 4;
+
+ pid = fork();
+ if (pid < 0) {
+ log_error("Failed to fork: %m");
+ free(page);
+ free(section);
+ continue;
+ }
+
+ if (pid == 0) {
+ /* Child */
+ execvp(args[0], (char**) args);
+ log_error("Failed to execute man: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ free(page);
+ free(section);
+
+ wait_for_terminate(pid, NULL);
+ } else
+ log_info("Can't show: %s", *p);
+ }
+}
+
static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
assert(name);
else if (streq(name, "Description"))
i->description = s;
else if (streq(name, "FragmentPath"))
- i->path = s;
-#ifdef HAVE_SYSV_COMPAT
- else if (streq(name, "SysVPath")) {
- i->is_sysv = true;
- i->path = s;
- }
-#endif
+ i->fragment_path = s;
+ else if (streq(name, "SourcePath"))
+ i->source_path = s;
else if (streq(name, "DefaultControlGroup"))
i->default_control_group = s;
else if (streq(name, "StatusText"))
LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
+ dbus_message_iter_next(&sub);
+ }
+ } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
+ streq(name, "Documentation")) {
+
+ DBusMessageIter sub;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
+ const char *s;
+ char **l;
+
+ dbus_message_iter_get_basic(&sub, &s);
+
+ l = strv_append(i->documentation, s);
+ if (!l)
+ return -ENOMEM;
+
+ strv_free(i->documentation);
+ i->documentation = l;
+
dbus_message_iter_next(&sub);
}
}
}
static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
- DBusMessage *m = NULL, *reply = NULL;
+ 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;
+ 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)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
r = 0;
- if (!show_properties)
- print_status_info(&info);
+ if (!show_properties) {
+ if (streq(verb, "help"))
+ show_unit_help(&info);
+ else
+ print_status_info(&info);
+ }
+
+ strv_free(info.documentation);
if (!streq_ptr(info.active_state, "active") &&
!streq_ptr(info.active_state, "reloading") &&
}
finish:
- if (m)
- dbus_message_unref(m);
+ if (reply)
+ dbus_message_unref(reply);
+
+ return r;
+}
+
+static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
+ DBusMessage *reply = NULL;
+ const char *path = NULL;
+ DBusError error;
+ int r;
+
+ dbus_error_init(&error);
+
+ 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)
+ 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;
+ }
+
+ r = show_one(verb, bus, path, false, new_line);
+finish:
if (reply)
dbus_message_unref(reply);
}
static int show(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
int r, ret = 0;
- DBusError error;
bool show_properties, new_line = false;
char **name;
assert(bus);
assert(args);
- dbus_error_init(&error);
-
- show_properties = !streq(args[0], "status");
+ show_properties = streq(args[0], "show");
if (show_properties)
pager_open_if_enabled();
/* If not argument is specified inspect the manager
* itself */
- ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
- goto finish;
+ return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
}
STRV_FOREACH(name, args+1) {
- const char *path = NULL;
uint32_t id;
if (safe_atou32(*name, &id) < 0) {
-
+ char *p, *n;
/* Interpret as unit name */
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LoadUnit"))) {
- log_error("Could not allocate message.");
- ret = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, name,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- ret = -ENOMEM;
- goto finish;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-
- if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
- log_error("Failed to issue method call: %s", bus_error_message(&error));
- ret = -EIO;
- goto finish;
- }
-
- dbus_error_free(&error);
-
- dbus_message_unref(m);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit"))) {
- log_error("Could not allocate message.");
- ret = -ENOMEM;
- goto finish;
- }
+ n = unit_name_mangle(*name);
+ p = unit_dbus_path_from_name(n ? n : *name);
+ free(n);
+ if (!p)
+ return log_oom();
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, name,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- ret = -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 = show_one(args[0], bus, p, show_properties, &new_line);
+ free(p);
- if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
- ret = 4; /* According to LSB: "program or service status is unknown" */
- else
- ret = -EIO;
- goto finish;
- }
- }
+ if (r != 0)
+ ret = r;
} else if (show_properties) {
/* Interpret as job id */
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetJob"))) {
- log_error("Could not allocate message.");
- ret = -ENOMEM;
- goto finish;
- }
+ char *p;
+ if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
+ return log_oom();
- if (!dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- ret = -ENOMEM;
- goto finish;
- }
+ r = show_one(args[0], bus, p, show_properties, &new_line);
+ free(p);
+
+ if (r != 0)
+ ret = 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));
- ret = -EIO;
- goto finish;
- }
} else {
/* Interpret as PID */
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnitByPID"))) {
- log_error("Could not allocate message.");
- ret = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_INVALID)) {
- log_error("Could not append arguments to message.");
- ret = -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));
- ret = -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));
- ret = -EIO;
- goto finish;
+ r = show_one_by_pid(args[0], bus, id, &new_line);
+ if (r != 0)
+ ret = r;
}
-
- if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
- ret = r;
-
- dbus_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
}
-finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
return ret;
}
static int dump(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ 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;
+ 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)
goto finish;
- }
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_STRING, &text,
fputs(text, stdout);
- r = 0;
-
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
}
static int snapshot(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *reply = NULL;
DBusError error;
int r;
- const char *name = "", *path, *id;
dbus_bool_t cleanup = FALSE;
DBusMessageIter iter, sub;
const char
+ *name = "", *path, *id,
*interface = "org.freedesktop.systemd1.Unit",
*property = "Id";
+ char *n;
dbus_error_init(&error);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "CreateSnapshot"))) {
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
-
if (strv_length(args) > 1)
name = args[1];
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_BOOLEAN, &cleanup,
- 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;
+ n = unit_name_mangle(name);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "CreateSnapshot",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, n ? (const char**) &n : &name,
+ DBUS_TYPE_BOOLEAN, &cleanup,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r)
goto finish;
- }
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_OBJECT_PATH, &path,
goto finish;
}
- dbus_message_unref(m);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "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;
- }
-
- 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;
- }
-
+ dbus_message_unref(reply);
+ 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)
+ goto finish;
+
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
log_error("Failed to parse reply.");
if (!arg_quiet)
puts(id);
- r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
}
static int delete_snapshot(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- int r;
+ DBusMessage *reply = NULL;
+ int r = 0;
DBusError error;
char **name;
- assert(bus);
assert(args);
dbus_error_init(&error);
STRV_FOREACH(name, args+1) {
const char *path = NULL;
+ char *n;
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit"))) {
- log_error("Could not allocate message.");
- 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;
- }
-
- 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;
+ n = unit_name_mangle(*name);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r)
goto finish;
- }
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
log_error("Failed to parse reply: %s", bus_error_message(&error));
r = -EIO;
+ dbus_message_unref(reply);
+ dbus_error_free(&error);
goto finish;
}
-
- dbus_message_unref(m);
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- path,
- "org.freedesktop.systemd1.Snapshot",
- "Remove"))) {
- 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;
- }
- dbus_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Snapshot",
+ "Remove",
+ NULL,
+ NULL,
+ DBUS_TYPE_INVALID);
+ if (r)
+ 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 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)
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);
+ int r = 0;
+ char **name, *n;
if (strv_length(args) <= 1)
return daemon_reload(bus, args);
STRV_FOREACH(name, args+1) {
- DBusMessage *reply;
-
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ResetFailedUnit"))) {
- log_error("Could not allocate message.");
- 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;
- }
-
- 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;
+ n = unit_name_mangle(*name);
+ r = bus_method_call_with_reply (
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ResetFailedUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, n ? &n : name,
+ DBUS_TYPE_INVALID);
+ free(n);
+ if (r)
goto finish;
- }
-
- dbus_message_unref(m);
- dbus_message_unref(reply);
- m = reply = NULL;
}
- r = 0;
-
finish:
- if (m)
- dbus_message_unref(m);
-
- dbus_error_free(&error);
-
return r;
}
static int show_enviroment(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
- DBusError error;
+ 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;
+ 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)
goto finish;
- }
if (!dbus_message_iter_init(reply, &iter) ||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
if (reply)
dbus_message_unref(reply);
- dbus_error_free(&error);
-
return r;
}
+static int switch_root(DBusConnection *bus, char **args) {
+ unsigned l;
+ const char *root, *init;
+
+ l = strv_length(args);
+ if (l < 2 || l > 3) {
+ log_error("Wrong number of arguments.");
+ return -EINVAL;
+ }
+
+ root = args[1];
+ init = l >= 3 ? args[2] : "";
+
+ 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);
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;
r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
-
return r;
}
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(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
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);
+ r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
if (r < 0)
return r;
r = 0;
-
for (f = 1; args[f]; f++) {
const char *name;
char *p;
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;
}
if (!isempty(arg_root))
argv[c++] = q = strappend("--root=", arg_root);
- argv[c++] = file_name_from_path(p);
+ argv[c++] = path_get_file_name(p);
argv[c++] =
streq(verb, "enable") ? "on" :
streq(verb, "disable") ? "off" : "--level=5";
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;
DBusMessage *m = NULL, *reply = NULL;
int r;
DBusError error;
+ char **mangled_names = NULL;
r = enable_sysv_units(args);
if (r < 0)
}
}
+ 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("Warning: unit files do not carry install information. No operation executed.");
+ log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
finish:
if (m)
unit_file_changes_free(changes, n_changes);
dbus_error_free(&error);
+
+ strv_free(mangled_names);
+
return r;
}
static int unit_is_enabled(DBusConnection *bus, char **args) {
DBusError error;
int r;
- DBusMessage *m = NULL, *reply = NULL;
+ DBusMessage *reply = NULL;
bool enabled;
char **name;
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;
+ "GetUnitFileState",
+ &reply,
+ NULL,
+ DBUS_TYPE_STRING, name,
+ DBUS_TYPE_INVALID);
+ if (r)
goto finish;
- }
if (!dbus_message_get_args(reply, &error,
DBUS_TYPE_STRING, &s,
goto finish;
}
- 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);
" --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"
" 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"
" reset-failed [NAME...] Reset failed state for all, one, or more\n"
" units\n"
" load [NAME...] Load one or more units\n\n"
" poweroff Shut down and power-off the system\n"
" reboot Shut down and reboot the system\n"
" kexec Shut down and reboot the system with kexec\n"
- " exit Ask for user instance termination\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"
+ " 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" :
" -H --halt Halt the machine\n"
" -P --poweroff Power-off the machine\n"
" -r --reboot Reboot the machine\n"
- " -h Equivalent to --poweroff, overriden by --halt\n"
+ " -h Equivalent to --poweroff, overridden by --halt\n"
" -k Don't halt/power-off/reboot, just send warnings\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
" -c Cancel a pending shutdown\n",
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_ROOT,
ARG_FULL,
ARG_NO_RELOAD,
- ARG_KILL_MODE,
ARG_KILL_WHO,
ARG_NO_ASK_PASSWORD,
ARG_FAILED,
ARG_RUNTIME,
- ARG_FOLLOW,
ARG_FORCE
};
{ "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 }
};
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;
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);
return -EINVAL;
default:
- log_error("Unknown option code %c", c);
+ log_error("Unknown option code '%c'.", c);
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 }
};
if (utmp_get_runlevel(&runlevel, NULL) >= 0)
if (runlevel == '0' || runlevel == '6')
- arg_immediate = true;
+ arg_force = 2;
while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
switch (c) {
break;
case 'f':
- arg_immediate = true;
+ arg_force = 2;
break;
case 'w':
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;
return -EINVAL;
default:
- log_error("Unknown option code %c", c);
+ log_error("Unknown option code '%c'.", c);
return -EINVAL;
}
}
return -EINVAL;
default:
- log_error("Unknown option code %c", c);
+ log_error("Unknown option code '%c'.", c);
return -EINVAL;
}
}
- 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;
return -EINVAL;
default:
- log_error("Unknown option code %c", c);
+ log_error("Unknown option code '%c'.", c);
return -EINVAL;
}
}
break;
if (i >= ELEMENTSOF(table)) {
- log_error("Unknown command %s.", argv[optind]);
+ log_error("Unknown command '%s'.", argv[optind]);
return -EINVAL;
}
return -EINVAL;
default:
- log_error("Unknown option code %c", c);
+ log_error("Unknown option code '%c'.", c);
return -EINVAL;
}
}
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;
}
{ "check", MORE, 2, check_unit },
{ "show", MORE, 1, show },
{ "status", MORE, 2, show },
+ { "help", MORE, 2, show },
{ "dump", EQUAL, 1, dump },
{ "dot", EQUAL, 1, dot },
{ "snapshot", LESS, 2, snapshot },
{ "poweroff", EQUAL, 1, start_special },
{ "reboot", EQUAL, 1, start_special },
{ "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 },
{ "preset", MORE, 2, enable_unit },
{ "mask", MORE, 2, enable_unit },
{ "unmask", MORE, 2, enable_unit },
- { "link", MORE, 2, enable_unit }
+ { "link", MORE, 2, enable_unit },
+ { "switch-root", MORE, 2, switch_root },
};
int left;
/* Special rule: no arguments means "list-units" */
i = 0;
else {
- if (streq(argv[optind], "help")) {
- systemctl_help();
- return 0;
+ if (streq(argv[optind], "help") && !argv[optind+1]) {
+ log_error("This command expects one or more "
+ "unit names. Did you mean --help?");
+ return -EINVAL;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
break;
if (i >= ELEMENTSOF(verbs)) {
- log_error("Unknown operation %s", argv[optind]);
+ log_error("Unknown operation '%s'.", argv[optind]);
return -EINVAL;
}
}
return 0;
}
- if (!bus) {
+ if (((!streq(verbs[i].verb, "reboot") &&
+ !streq(verbs[i].verb, "halt") &&
+ !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
log_error("Failed to get D-Bus connection: %s",
dbus_error_is_set(error) ? error->message : "No connection to service manager.");
return -EIO;
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... */
if (arg_when <= 0 &&
!arg_dry &&
- !arg_immediate &&
+ !arg_force &&
(arg_action == ACTION_POWEROFF ||
arg_action == ACTION_REBOOT)) {
r = reboot_with_logind(bus, arg_action);
}
}
- if (!arg_dry && !arg_immediate)
+ if (!arg_dry && !arg_force)
return start_with_fallback(bus);
if (!arg_no_wtmp) {
}
}
- if (!arg_no_sync)
- sync();
-
if (arg_dry)
return 0;
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: