#include "list.h"
static const char *arg_type = NULL;
-static const char *arg_property = NULL;
+static char **arg_property = NULL;
static bool arg_all = false;
-static bool arg_replace = false;
+static bool arg_fail = false;
static bool arg_session = false;
static bool arg_no_block = false;
static bool arg_immediate = false;
static bool arg_no_wall = false;
static bool arg_dry = false;
static bool arg_quiet = false;
+static char arg_full = false;
static char **arg_wall = NULL;
-enum action {
+static enum action {
ACTION_INVALID,
ACTION_SYSTEMCTL,
ACTION_HALT,
ACTION_RUNLEVEL,
_ACTION_MAX
} arg_action = ACTION_SYSTEMCTL;
+static enum dot {
+ DOT_ALL,
+ DOT_ORDER,
+ DOT_REQUIRE
+} arg_dot = DOT_ALL;
static bool private_bus = false;
+static const char *ansi_highlight(bool b) {
+ static int t = -1;
+
+ if (_unlikely_(t < 0))
+ t = isatty(STDOUT_FILENO) > 0;
+
+ if (!t)
+ return "";
+
+ return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
+}
+
static bool error_is_no_service(DBusError *error) {
assert(error);
dbus_message_iter_recurse(&iter, &sub);
- printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
+ if (isatty(STDOUT_FILENO))
+ printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
- const char *id, *description, *load_state, *active_state, *sub_state, *unit_state, *job_type, *job_path, *dot;
+ const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path, *job_type, *job_path, *dot;
uint32_t job_id;
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
- bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_state, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) {
if ((!arg_type || ((dot = strrchr(id, '.')) &&
streq(dot+1, arg_type))) &&
- (arg_all || !streq(active_state, "inactive"))) {
-
+ (arg_all || !(streq(active_state, "inactive") || following[0]) || job_id > 0)) {
+ char *e;
int a = 0, b = 0;
if (streq(active_state, "maintenance"))
- fputs(ANSI_HIGHLIGHT_ON, stdout);
+ fputs(ansi_highlight(true), stdout);
- printf("%-45s %-6s %-12s %-12s%n", id, load_state, active_state, sub_state, &a);
+ e = arg_full ? NULL : ellipsize(id, 45, 33);
+ printf("%-45s %-6s %-12s %-12s%n", e ? e : id, load_state, active_state, sub_state, &a);
+ free(e);
if (job_id != 0)
- printf(" %-15s%n", job_type, &b);
+ printf(" => %-12s%n", job_type, &b);
else
b = 1 + 15;
}
if (streq(active_state, "maintenance"))
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
+ fputs(ansi_highlight(false), stdout);
fputs("\n", stdout);
k++;
dbus_message_iter_next(&sub);
}
- if (arg_all)
- printf("\n%u units listed.\n", k);
- else
- printf("\n%u live units listed. Pass --all to see dead units, too.\n", k);
+ if (isatty(STDOUT_FILENO)) {
+
+ printf("\nLOAD = Load State, reflects whether the unit configuration was properly loaded.\n"
+ "ACTIVE = Active State, the high-level unit activation state, i.e. generalization of the substate.\n"
+ "SUB = Substate, the low-level unit activation state, possible values depend on unit type.\n"
+ "JOB = Job, shows pending jobs for the unit.\n");
+
+ if (arg_all)
+ printf("\n%u units listed.\n", k);
+ else
+ printf("\n%u units listed. Pass --all to see inactive units, too.\n", k);
+ }
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
+ static const char * const colors[] = {
+ "Requires", "[color=\"black\"]",
+ "RequiresOverridable", "[color=\"black\"]",
+ "Requisite", "[color=\"darkblue\"]",
+ "RequisiteOverridable", "[color=\"darkblue\"]",
+ "Wants", "[color=\"darkgrey\"]",
+ "Conflicts", "[color=\"red\"]",
+ "After", "[color=\"green\"]"
+ };
+
+ const char *c = NULL;
+ unsigned i;
+
+ assert(name);
+ assert(prop);
+ assert(iter);
+
+ for (i = 0; i < ELEMENTSOF(colors); i += 2)
+ if (streq(colors[i], prop)) {
+ c = colors[i+1];
+ break;
+ }
+
+ if (!c)
+ return 0;
+
+ if (arg_dot != DOT_ALL)
+ if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
+ return 0;
+
+ switch (dbus_message_iter_get_arg_type(iter)) {
+
+ case DBUS_TYPE_ARRAY:
+
+ if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
+ DBusMessageIter sub;
+
+ dbus_message_iter_recurse(iter, &sub);
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *s;
+
+ assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic(&sub, &s);
+ printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
+
+ dbus_message_iter_next(&sub);
+ }
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int dot_one(DBusConnection *bus, const char *name, const char *path) {
+ DBusMessage *m = NULL, *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", error.message);
+ r = -EIO;
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *prop;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&sub2, &sub3);
+
+ if (dot_one_property(name, prop, &sub3)) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+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, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ DBusError error;
+ 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", error.message);
+ r = -EIO;
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ printf("digraph systemd {\n");
+
+ dbus_message_iter_recurse(&iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+ const char *id, *description, *load_state, *active_state, *sub_state, *unit_path;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
+ log_error("Failed to parse reply.");
+ r = -EIO;
+ goto finish;
+ }
+
+ if ((r = dot_one(bus, id, unit_path)) < 0)
+ goto finish;
+
+ /* printf("\t\"%s\";\n", id); */
+ dbus_message_iter_next(&sub);
+ }
+
+ printf("}\n");
+
+ log_info(" Color legend: black = Requires\n"
+ " dark blue = Requisite\n"
+ " dark grey = Wants\n"
+ " red = Conflicts\n"
+ " green = After\n");
+
+ if (isatty(fileno(stdout)))
+ log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
+ "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
r = 0;
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
const char *name, *type, *state, *job_path, *unit_path;
uint32_t id;
+ char *e;
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
log_error("Failed to parse reply.");
goto finish;
}
- printf("%4u %-45s %-17s %-7s\n", id, name, type, state);
+ e = arg_full ? NULL : ellipsize(name, 45, 33);
+ printf("%4u %-45s %-17s %-7s\n", id, e ? e : name, type, state);
+ free(e);
+
k++;
dbus_message_iter_next(&sub);
return r;
}
+static bool unit_need_daemon_reload(DBusConnection *bus, const char *unit) {
+ DBusMessage *m, *reply;
+ dbus_bool_t b = FALSE;
+ DBusMessageIter iter, sub;
+ const char
+ *interface = "org.freedesktop.systemd1.Unit",
+ *property = "NeedDaemonReload",
+ *path;
+
+ /* 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)))
+ goto finish;
+
+ if (!dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ 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)))
+ goto finish;
+
+ if (!dbus_message_iter_init(reply, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ goto finish;
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+ goto finish;
+
+ dbus_message_iter_get_basic(&sub, &b);
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ return b;
+}
+
typedef struct WaitData {
Set *set;
bool failed;
DBusMessage *m = NULL, *reply = NULL;
DBusError error;
+ const char *path;
int r;
assert(bus);
goto finish;
}
+ if (!dbus_message_get_args(reply, &error,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID)) {
+ log_error("Failed to parse reply: %s", error.message);
+ r = -EIO;
+ goto finish;
+ }
+
+ if (unit_need_daemon_reload(bus, name))
+ log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
+ arg_session ? "--session" : "--system");
+
if (!arg_no_block) {
- const char *path;
char *p;
- if (!dbus_message_get_args(reply, &error,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse reply: %s", error.message);
- r = -EIO;
- goto finish;
- }
-
if (!(p = strdup(path))) {
log_error("Failed to duplicate path.");
r = -ENOMEM;
[ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
[ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
[ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
- [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_SERVICE,
+ [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
[ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
};
if (arg_action == ACTION_SYSTEMCTL) {
method =
- streq(args[0], "stop") ? "StopUnit" :
- streq(args[0], "reload") ? "ReloadUnit" :
- streq(args[0], "restart") ? "RestartUnit" :
- "StartUnit";
+ streq(args[0], "stop") ? "StopUnit" :
+ streq(args[0], "reload") ? "ReloadUnit" :
+ streq(args[0], "restart") ? "RestartUnit" :
+ streq(args[0], "try-restart") ? "TryRestartUnit" :
+ streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
+ streq(args[0], "reload-or-try-restart") ||
+ streq(args[0], "force-reload") ||
+ streq(args[0], "condrestart") ? "ReloadOrTryRestartUnit" :
+ "StartUnit";
mode =
(streq(args[0], "isolate") ||
streq(args[0], "rescue") ||
streq(args[0], "emergency")) ? "isolate" :
- arg_replace ? "replace" :
- "fail";
+ arg_fail ? "fail" :
+ "replace";
one_name = table[verb_to_action(args[0])];
}
static int start_special(DBusConnection *bus, char **args, unsigned n) {
+ int r;
+
assert(bus);
assert(args);
- warn_wall(verb_to_action(args[0]));
+ r = start_unit(bus, args, n);
+
+ if (r >= 0)
+ warn_wall(verb_to_action(args[0]));
- return start_unit(bus, args, n);
+ return r;
}
static int check_unit(DBusConnection *bus, char **args, unsigned n) {
char *path;
char **argv;
+ bool ignore;
+
usec_t start_timestamp;
usec_t exit_timestamp;
pid_t pid;
unsigned n;
uint32_t pid;
int32_t code, status;
+ dbus_bool_t ignore;
assert(i);
assert(i);
}
if (!dbus_message_iter_next(&sub2) ||
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
return -EIO;
+ i->ignore = ignore;
i->start_timestamp = (usec_t) start_timestamp;
i->exit_timestamp = (usec_t) exit_timestamp;
i->pid = (pid_t) pid;
const char *fragment_path;
const char *default_control_group;
+ bool need_daemon_reload;
+
/* Service */
pid_t main_pid;
pid_t control_pid;
static void print_status_info(UnitStatusInfo *i) {
ExecStatusInfo *p;
- int r;
assert(i);
if (i->fragment_path)
printf("\t Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
else if (streq_ptr(i->load_state, "failed"))
- printf("\t Loaded: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n", strna(i->load_state));
+ printf("\t Loaded: %s%s%s\n",
+ ansi_highlight(true),
+ strna(i->load_state),
+ ansi_highlight(false));
else
printf("\t Loaded: %s\n", strna(i->load_state));
if (streq_ptr(i->active_state, "maintenance")) {
if (streq_ptr(i->active_state, i->sub_state))
- printf("\t Active: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n",
- strna(i->active_state));
+ printf("\t Active: %s%s%s\n",
+ ansi_highlight(true),
+ strna(i->active_state),
+ ansi_highlight(false));
else
- printf("\t Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
+ printf("\t Active: %s%s (%s)%s\n",
+ ansi_highlight(true),
strna(i->active_state),
- strna(i->sub_state));
+ strna(i->sub_state),
+ ansi_highlight(false));
} else {
if (streq_ptr(i->active_state, i->sub_state))
printf("\t Active: %s\n",
printf("status=%i", i->exit_status);
else
printf("signal=%s", signal_to_string(i->exit_status));
- printf(")");
- }
+ printf(")"); }
}
if (i->main_pid > 0 && i->control_pid > 0)
else
c = 0;
- if ((r = cg_init()) < 0)
- log_error("Failed to initialize libcg: %s", strerror(-r));
- else
- show_cgroup_recursive(i->default_control_group, "\t\t ", c);
+ show_cgroup_by_path(i->default_control_group, "\t\t ", c);
}
+
+ if (i->need_daemon_reload)
+ printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
+ ansi_highlight(true),
+ ansi_highlight(false),
+ arg_session ? "--session" : "--system");
}
static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
if (streq(name, "Accept"))
i->accept = b;
+ else if (streq(name, "NeedDaemonReload"))
+ i->need_daemon_reload = b;
break;
}
/* This is a low-level property printer, see
* print_status_info() for the nicer output */
- if (arg_property && !streq(name, arg_property))
+ if (arg_property && !strv_find(arg_property, name))
return 0;
switch (dbus_message_iter_get_arg_type(iter)) {
t = strv_join(info.argv, " ");
- printf("%s={ path=%s ; argv[]=%s; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
+ printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
name,
strna(info.path),
strna(t),
+ yes_no(info.ignore),
strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
(unsigned) info. pid,
assert(arg_action == ACTION_SYSTEMCTL);
method =
- streq(args[0], "clear-jobs") ? "ClearJobs" :
- streq(args[0], "daemon-reload") ? "Reload" :
- streq(args[0], "daemon-reexec") ? "Reexecute" :
- "Exit";
+ streq(args[0], "clear-jobs") ? "ClearJobs" :
+ streq(args[0], "daemon-reload") ? "Reload" :
+ streq(args[0], "daemon-reexec") ? "Reexecute" :
+ streq(args[0], "reset-maintenance") ? "ResetMaintenance" :
+ "Exit";
}
if (!(m = dbus_message_new_method_call(
return r;
}
+static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ unsigned i;
+ int r;
+ DBusError error;
+
+ assert(bus);
+ dbus_error_init(&error);
+
+ if (n <= 1)
+ return clear_jobs(bus, args, n);
+
+ for (i = 1; i < n; i++) {
+
+ if (!(m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ResetMaintenanceUnit"))) {
+ log_error("Could not allocate message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, args + i,
+ 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", error.message);
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
DBusMessage *m = NULL, *reply = NULL;
DBusError error;
static int systemctl_help(void) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
- "Send control commands to the systemd manager.\n\n"
+ "Send control commands to or query the systemd manager.\n\n"
" -h --help Show this help\n"
" -t --type=TYPE List only units of a particular type\n"
" -p --property=NAME Show only properties by this name\n"
" -a --all Show all units/properties, including dead/empty ones\n"
- " --replace When installing a new job, replace existing conflicting ones\n"
+ " --full Don't ellipsize unit names.\n"
+ " --fail When installing a new job, fail if conflicting jobs are\n"
+ " pending\n"
" --system Connect to system bus\n"
" --session Connect to session bus\n"
+ " --order When generating graph for dot, show only order\n"
+ " --require When generating graph for dot, show only requirement\n"
" -q --quiet Suppress output\n"
" --no-block Do not wait until operation finished\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n\n"
" list-units List units\n"
" start [NAME...] Start one or more units\n"
" stop [NAME...] Stop one or more units\n"
- " restart [NAME...] Restart one or more units\n"
" reload [NAME...] Reload one or more units\n"
+ " restart [NAME...] Start or restart one or more units\n"
+ " try-restart [NAME...] Restart one or more units if active\n"
+ " reload-or-restart [NAME...] Reload one or more units is possible,\n"
+ " otherwise start or restart\n"
+ " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
+ " otherwise restart if active\n"
" isolate [NAME] Start one unit and stop all others\n"
- " check [NAME...] Check whether any of the passed units are active\n"
+ " check [NAME...] Check whether units are active\n"
" status [NAME...] Show status of one or more units\n"
- " show [NAME...|JOB...] Show properties of one or more units/jobs/manager\n"
+ " show [NAME...|JOB...] Show properties of one or more\n"
+ " units/jobs/manager\n"
+ " reset-maintenance [NAME...] Reset maintenance state for all, one\n"
+ " or more units\n"
" load [NAME...] Load one or more units\n"
" list-jobs List jobs\n"
" cancel [JOB...] Cancel one or more jobs\n"
" clear-jobs Cancel all jobs\n"
" monitor Monitor unit/job changes\n"
" dump Dump server status\n"
+ " dot Dump dependency graph for dot(1)\n"
" snapshot [NAME] Create a snapshot\n"
" delete [NAME...] Remove one or more snapshots\n"
" daemon-reload Reload systemd manager configuration\n"
" halt Shut down and halt the system\n"
" poweroff Shut down and power-off the system\n"
" reboot Shut down and reboot the system\n"
- " default Enter default mode\n"
- " rescue Enter rescue mode\n"
- " emergency Enter emergency mode\n",
+ " rescue Enter system rescue mode\n"
+ " emergency Enter system emergency mode\n"
+ " default Enter system default mode\n",
program_invocation_short_name);
return 0;
static int systemctl_parse_argv(int argc, char *argv[]) {
enum {
- ARG_REPLACE = 0x100,
+ ARG_FAIL = 0x100,
ARG_SESSION,
ARG_SYSTEM,
ARG_NO_BLOCK,
- ARG_NO_WALL
+ ARG_NO_WALL,
+ ARG_ORDER,
+ ARG_REQUIRE,
+ ARG_FULL
};
static const struct option options[] = {
{ "type", required_argument, NULL, 't' },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
- { "replace", no_argument, NULL, ARG_REPLACE },
+ { "full", no_argument, NULL, ARG_FULL },
+ { "fail", no_argument, NULL, ARG_FAIL },
{ "session", no_argument, NULL, ARG_SESSION },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{ "quiet", no_argument, NULL, 'q' },
+ { "order", no_argument, NULL, ARG_ORDER },
+ { "require", no_argument, NULL, ARG_REQUIRE },
{ NULL, 0, NULL, 0 }
};
arg_type = optarg;
break;
- case 'p':
- arg_property = optarg;
+ case 'p': {
+ char **l;
+
+ if (!(l = strv_append(arg_property, optarg)))
+ return -ENOMEM;
+
+ strv_free(arg_property);
+ arg_property = l;
/* If the user asked for a particular
* property, show it to him, even if it is
* empty. */
arg_all = true;
break;
+ }
case 'a':
arg_all = true;
break;
- case ARG_REPLACE:
- arg_replace = true;
+ case ARG_FAIL:
+ arg_fail = true;
break;
case ARG_SESSION:
arg_no_wall = true;
break;
+ case ARG_ORDER:
+ arg_dot = DOT_ORDER;
+ break;
+
+ case ARG_REQUIRE:
+ arg_dot = DOT_REQUIRE;
+ break;
+
+ case ARG_FULL:
+ arg_full = true;
+ break;
+
case 'q':
arg_quiet = true;
break;
{ "stop", MORE, 2, start_unit },
{ "reload", MORE, 2, start_unit },
{ "restart", MORE, 2, start_unit },
+ { "try-restart", MORE, 2, start_unit },
+ { "reload-or-restart", MORE, 2, start_unit },
+ { "reload-or-try-restart", MORE, 2, start_unit },
+ { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
+ { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
{ "isolate", EQUAL, 2, start_unit },
{ "check", MORE, 2, check_unit },
{ "show", MORE, 1, show },
{ "status", MORE, 2, show },
{ "monitor", EQUAL, 1, monitor },
{ "dump", EQUAL, 1, dump },
+ { "dot", EQUAL, 1, dot },
{ "snapshot", LESS, 2, snapshot },
{ "delete", MORE, 2, delete_snapshot },
{ "daemon-reload", EQUAL, 1, clear_jobs },
{ "reboot", EQUAL, 1, start_special },
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
- { "emergency", EQUAL, 1, start_special }
+ { "emergency", EQUAL, 1, start_special },
+ { "reset-maintenance", MORE, 1, reset_maintenance },
};
int left;
static int start_with_fallback(DBusConnection *bus) {
int r;
- warn_wall(arg_action);
if (bus) {
/* First, try systemd via D-Bus. */
if ((r = start_unit(bus, NULL, 0)) > 0)
- return 0;
+ goto done;
/* Hmm, talking to systemd via D-Bus didn't work. Then
* let's try to talk to Upstart via D-Bus. */
if ((r = talk_upstart()) > 0)
- return 0;
+ goto done;
}
/* Nothing else worked, so let's try
* /dev/initctl */
if ((r = talk_initctl()) != 0)
- return 0;
+ goto done;
log_error("Failed to talk to init daemon.");
return -EIO;
+
+done:
+ warn_wall(arg_action);
+ return 0;
}
static int halt_main(DBusConnection *bus) {
dbus_shutdown();
+ strv_free(arg_property);
+
return retval;
}