#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"
static const char *arg_type = 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;
ACTION_REBOOT,
ACTION_KEXEC,
ACTION_EXIT,
+ ACTION_SUSPEND,
+ ACTION_HIBERNATE,
ACTION_RUNLEVEL2,
ACTION_RUNLEVEL3,
ACTION_RUNLEVEL4,
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) {
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)));
}
} 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);
} 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)
d->result = strdup(result);
}
#ifndef LEGACY
dbus_error_free(&error);
+ if (dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ 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);
+
+ 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,
* 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");
return r;
}
+static int get_unit_path(
+ DBusConnection *bus,
+ const char *name,
+ char **unit_path) {
+
+ DBusError error;
+ DBusMessage *m = NULL, *reply = NULL;
+ char *path;
+ int r = 0;
+
+ assert(bus);
+ assert(name);
+ assert(unit_path);
+
+ 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;
+ }
+
+ 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) {
+ if (streq(error.name, BUS_ERROR_NO_SUCH_UNIT))
+ r = -EINVAL;
+ else {
+ 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;
+ }
+
+ *unit_path = strdup(path);
+ if (!(*unit_path)) {
+ log_error("Failed to duplicate unit path");
+ r = -ENOMEM;
+ }
+finish:
+ if (m)
+ dbus_message_unref(m);
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int check_one_unit(DBusConnection *bus, char *name, bool quiet) {
+ DBusMessage *m = NULL, *reply = NULL;
+ DBusError error;
+ 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" */
+
+ 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;
+ }
+
+ 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) {
+ /* Hmm, cannot figure out anything about this unit... */
+ if (!quiet)
+ puts("unknown");
+
+ 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.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;
+ }
+
+ 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;
+ }
+
+ 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 (!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;
+}
+
+static void check_listening_sockets(
+ DBusConnection *bus,
+ const char *unit_name) {
+
+ DBusError error;
+ DBusMessage *m = NULL, *reply = NULL;
+ DBusMessageIter iter, sub;
+ char *service_trigger = NULL;
+ const char *interface = "org.freedesktop.systemd1.Unit",
+ *triggered_by_property = "TriggeredBy";
+
+ char *unit_path = NULL;
+ bool print_warning_label = true;
+
+ dbus_error_init(&error);
+
+ if (get_unit_path(bus, unit_name, &unit_path) < 0)
+ goto finish;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+
+ }
+
+ 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) {
+ int r;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+ log_error("Failed to parse reply: %s", bus_error_message(&error));
+ goto finish;
+ }
+
+ dbus_message_iter_get_basic(&sub, &service_trigger);
+
+ if (!endswith(service_trigger, ".socket"))
+ goto next;
+
+ r = check_one_unit(bus, service_trigger, true);
+ if (r < 0)
+ goto finish;
+ if (r == 0) {
+ if (print_warning_label) {
+ log_warning("There are listening sockets associated with %s :", unit_name);
+ print_warning_label = false;
+ }
+ log_warning("%s", service_trigger);
+ }
+next:
+ dbus_message_iter_recurse(&iter, &sub);
+ iter = 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(
DBusConnection *bus,
const char *method,
}
}
+ /* When stopping unit check if we have some listening sockets active */
+ if (streq(method, "StopUnit") && !arg_quiet)
+ check_listening_sockets(bus, name);
+
r = 0;
finish:
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;
}
[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
};
int r, ret = 0;
method = "PowerOff";
break;
+ case ACTION_SUSPEND:
+ method = "Suspend";
+ break;
+
+ case ACTION_HIBERNATE:
+ method = "Hibernate";
+ break;
+
default:
return -EINVAL;
}
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)) {
r = reboot_with_logind(bus, a);
if (r >= 0)
return r;
if (r >= 0)
warn_wall(a);
- 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;
-
- 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;
- }
+ return r;
+}
- dbus_message_iter_get_basic(&sub, &state);
+static int check_unit(DBusConnection *bus, char **args) {
+ char **name;
+ int r = 3; /* According to LSB: "program is not running" */
- if (!arg_quiet)
- puts(state);
+ assert(bus);
+ assert(args);
- if (streq(state, "active") || streq(state, "reloading"))
+ STRV_FOREACH(name, args+1) {
+ int state = check_one_unit(bus, *name, arg_quiet);
+ if (state < 0)
+ return state;
+ if (state == 0)
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);
-
return r;
}
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);
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);
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
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_error("Out of memory.");
+ return;
+ }
+
+ section = strndup(e + 1, *p + k - e - 2);
+ if (!section) {
+ free(page);
+ log_error("Out of memory");
+ 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);
}
}
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") &&
return r;
}
-static int show(DBusConnection *bus, char **args) {
+static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
DBusMessage *m = NULL, *reply = NULL;
- int r, ret = 0;
+ const char *path = NULL;
DBusError 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;
+ }
+
+ 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 (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int show(DBusConnection *bus, char **args) {
+ int r, ret = 0;
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) {
/* 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;
- }
-
- 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;
- }
+ char *e, *p;
+ e = bus_path_escape(*name);
+ if (!e)
+ return -ENOMEM;
+ p = strappend("/org/freedesktop/systemd1/unit/", e);
+ free(e);
+ if (!p)
+ 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 = 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 -ENOMEM;
- 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;
}
return r;
}
+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);
+
+ 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] : "";
+
+ 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;
+ }
+
+ 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 set_environment(DBusConnection *bus, char **args) {
DBusMessage *m = NULL, *reply = NULL;
DBusError error;
* afterwards only the native units remain */
zero(paths);
- r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
+ r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
if (r < 0)
return r;
r = 0;
-
for (f = 1; args[f]; f++) {
const char *name;
char *p;
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";
" 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",
program_invocation_short_name);
return 0;
" -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",
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':
{ "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 },
{ "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++)
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;
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) {