static bool arg_all = false;
static bool arg_replace = false;
static bool arg_session = false;
-static bool arg_block = false;
+static bool arg_no_block = false;
static bool arg_immediate = false;
static bool arg_no_wtmp = false;
static bool arg_no_sync = false;
static bool arg_no_wall = false;
static bool arg_dry = false;
+static bool arg_quiet = false;
static char **arg_wall = NULL;
enum action {
ACTION_INVALID,
return r;
}
+typedef struct WaitData {
+ Set *set;
+ bool failed;
+} WaitData;
+
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
DBusError error;
- Set *s = data;
+ WaitData *d = data;
assert(connection);
assert(message);
- assert(s);
+ assert(d);
dbus_error_init(&error);
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
const char *path;
+ dbus_bool_t success = true;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_BOOLEAN, &success,
DBUS_TYPE_INVALID))
log_error("Failed to parse message: %s", error.message);
else {
char *p;
- if ((p = set_remove(s, (char*) path)))
+ if ((p = set_remove(d->set, (char*) path)))
free(p);
+
+ if (!success)
+ d->failed = true;
}
}
static int wait_for_jobs(DBusConnection *bus, Set *s) {
int r;
+ WaitData d;
assert(bus);
assert(s);
- if (!dbus_connection_add_filter(bus, wait_filter, s, NULL)) {
+ zero(d);
+ d.set = s;
+ d.failed = false;
+
+ if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
log_error("Failed to add filter.");
r = -ENOMEM;
goto finish;
dbus_connection_read_write_dispatch(bus, -1))
;
- r = 0;
+ if (!arg_quiet && d.failed)
+ log_error("Job failed, see logs for details.");
+
+ r = d.failed ? -EIO : 0;
finish:
/* This is slightly dirty, since we don't undo the filter registration. */
assert(method);
assert(name);
assert(mode);
- assert(!arg_block || s);
+ assert(arg_no_block || s);
dbus_error_init(&error);
goto finish;
}
- if (arg_block) {
+ if (!arg_no_block) {
const char *path;
char *p;
one_name = table[arg_action];
}
- if (arg_block) {
+ if (!arg_no_block) {
if ((r = enable_wait_for_jobs(bus)) < 0) {
log_error("Could not watch jobs: %s", strerror(-r));
goto finish;
goto finish;
}
- if (arg_block)
+ if (!arg_no_block)
r = wait_for_jobs(bus, s);
finish:
return start_unit(bus, args, n);
}
+static int check_unit(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ const char
+ *interface = "org.freedesktop.systemd1.Unit",
+ *property = "ActiveState";
+ int r = -EADDRNOTAVAIL;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ for (i = 1; i < n; i++) {
+ 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, &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))) {
+
+ /* Hmm, cannot figure out anything about this unit... */
+ if (!arg_quiet)
+ puts("unknown");
+
+ continue;
+ }
+
+ 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;
+ }
+
+ 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", error.message);
+ 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") || startswith(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);
+
+ return r;
+
+}
+
static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
DBusError error;
DBusMessage *m = NULL, *reply = NULL;
}
dbus_message_iter_get_basic(&sub, &id);
- puts(id);
+
+ if (!arg_quiet)
+ puts(id);
+ r = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
+ DBusMessage *m = NULL, *reply = NULL;
+ int r;
+ DBusError error;
+ unsigned i;
+
+ assert(bus);
+ assert(args);
+
+ dbus_error_init(&error);
+
+ for (i = 1; i < n; i++) {
+ const char *path = NULL;
+
+ 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, &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;
+ }
+
+ 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;
+ }
+
+ 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", error.message);
+ r = -EIO;
+ goto finish;
+ }
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+ }
+
r = 0;
finish:
static int systemctl_help(void) {
- printf("%s [options]\n\n"
- "Send control commands to the init daemon.\n\n"
+ printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+ "Send control commands to the systemd manager.\n\n"
" -h --help Show this help\n"
" -t --type=TYPE List only units of a particular type\n"
" -a --all Show all units, including dead ones\n"
" --replace When installing a new job, replace existing conflicting ones\n"
" --system Connect to system bus\n"
" --session Connect to session bus\n"
- " --block Wait until operation finished\n"
- " --no-wall Don't send wall message before reboot/halt/power-off\n\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"
"Commands:\n"
" list-units List units\n"
" list-jobs List jobs\n"
" restart [NAME...] Restart one or more units\n"
" reload [NAME...] Reload one or more units\n"
" isolate [NAME] Start one unit and stop all others\n"
+ " check [NAME...] Check whether any of the passed units are active\n"
" monitor Monitor unit/job changes\n"
" dump Dump server status\n"
" snapshot [NAME] Create a snapshot\n"
- " daemon-reload Reload init daemon configuration\n"
- " daemon-reexec Reexecute init daemon\n"
- " daemon-exit Ask the init daemon to quit\n"
+ " delete [NAME...] Remove one or more snapshots\n"
+ " daemon-reload Reload systemd manager configuration\n"
+ " daemon-reexec Reexecute systemd manager\n"
+ " daemon-exit Ask the systemd manager to quit\n"
" show-environment Dump environment\n"
" set-environment [NAME=VALUE...] Set one or more environment variables\n"
" unset-environment [NAME...] Unset one or more environment variables\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"
- " poweroff Shut down and power off the system\n"
" default Enter default mode\n"
" rescue Enter rescue mode\n"
" emergency Enter emergency mode\n",
static int halt_help(void) {
- printf("%s [options]\n\n"
+ printf("%s [OPTIONS...]\n\n"
"%s the system.\n\n"
" --help Show this help\n"
" --halt Halt the machine\n"
" -p --poweroff Switch off the machine\n"
" --reboot Reboot the machine\n"
- " -f --force Force immediate reboot/halt/power-off\n"
- " -w --wtmp-only Don't reboot/halt/power-off, just write wtmp record\n"
+ " -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 reboot/halt/power-off\n"
- " --no-wall Don't send wall message before reboot/halt/power-off\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" :
arg_action == ACTION_POWEROFF ? "Power off" :
static int shutdown_help(void) {
- printf("%s [options] [now] [WALL...]\n\n"
+ printf("%s [OPTIONS...] [now] [WALL...]\n\n"
"Shut down the system.\n\n"
" --help Show this help\n"
" -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"
- " -k Don't reboot/halt/power-off, just send warnings\n"
- " --no-wall Don't send wall message before reboot/halt/power-off\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",
program_invocation_short_name);
return 0;
static int telinit_help(void) {
- printf("%s [options]\n\n"
+ printf("%s [OPTIONS...] {COMMAND}\n\n"
"Send control commands to the init daemon.\n\n"
" --help Show this help\n"
- " --no-wall Don't send wall message before reboot/halt/power-off\n\n"
+ " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
"Commands:\n"
" 0 Power-off the machine\n"
" 6 Reboot the machine\n"
static int runlevel_help(void) {
- printf("%s [options]\n\n"
+ printf("%s [OPTIONS...]\n\n"
"Prints the previous and current runlevel of the init system.\n\n"
" --help Show this help\n",
program_invocation_short_name);
ARG_REPLACE = 0x100,
ARG_SESSION,
ARG_SYSTEM,
- ARG_BLOCK,
+ ARG_NO_BLOCK,
ARG_NO_WALL
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "type", required_argument, NULL, 't' },
- { "all", no_argument, NULL, 'a' },
- { "replace", no_argument, NULL, ARG_REPLACE },
- { "session", no_argument, NULL, ARG_SESSION },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "block", no_argument, NULL, ARG_BLOCK },
- { "no-wall", no_argument, NULL, ARG_NO_WALL },
- { NULL, 0, NULL, 0 }
+ { "help", no_argument, NULL, 'h' },
+ { "type", required_argument, NULL, 't' },
+ { "all", no_argument, NULL, 'a' },
+ { "replace", no_argument, NULL, ARG_REPLACE },
+ { "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' },
+ { NULL, 0, NULL, 0 }
};
int c;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hta", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "htaq", options, NULL)) >= 0) {
switch (c) {
arg_session = false;
break;
- case ARG_BLOCK:
- arg_block = true;
+ case ARG_NO_BLOCK:
+ arg_no_block = true;
break;
case ARG_NO_WALL:
arg_no_wall = true;
break;
+ case 'q':
+ arg_quiet = true;
+ break;
+
case '?':
return -EINVAL;
}
if (optind >= argc) {
- log_error("Argument missing.");
+ telinit_help();
return -EINVAL;
}
{ "reload", MORE, 2, start_unit },
{ "restart", MORE, 2, start_unit },
{ "isolate", EQUAL, 2, start_unit },
+ { "check", MORE, 2, check_unit },
{ "monitor", EQUAL, 1, monitor },
{ "dump", EQUAL, 1, dump },
{ "snapshot", LESS, 2, snapshot },
+ { "delete", MORE, 2, delete_snapshot },
{ "daemon-reload", EQUAL, 1, clear_jobs },
{ "daemon-reexec", EQUAL, 1, clear_jobs },
{ "daemon-exit", EQUAL, 1, clear_jobs },
/* Special rule: no arguments means "list-units" */
i = 0;
else {
+ if (streq(argv[optind], "help")) {
+ systemctl_help();
+ return 0;
+ }
+
for (i = 0; i < ELEMENTSOF(verbs); i++)
if (streq(argv[optind], verbs[i].verb))
break;