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;
static enum action {
ACTION_INVALID,
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_path, *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_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 ||
if ((!arg_type || ((dot = strrchr(id, '.')) &&
streq(dot+1, arg_type))) &&
- (arg_all || !streq(active_state, "inactive") || job_id > 0)) {
-
+ (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);
- 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(" => %-12s%n", job_type, &b);
dbus_message_iter_next(&sub);
}
- 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 scheduled jobs for the unit.\n");
+ if (isatty(STDOUT_FILENO)) {
- 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);
+ 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;
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;
const char *fragment_path;
const char *default_control_group;
+ bool need_daemon_reload;
+
/* Service */
pid_t main_pid;
pid_t control_pid;
show_cgroup_by_path(i->default_control_group, "\t\t ", c);
}
+
+ if (i->need_daemon_reload)
+ printf("\n" ANSI_HIGHLIGHT_ON "Warning:" ANSI_HIGHLIGHT_OFF " Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
+ 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;
}
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"
+ " --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"
" status [NAME...] Show status of one or more units\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"
ARG_NO_BLOCK,
ARG_NO_WALL,
ARG_ORDER,
- ARG_REQUIRE
+ ARG_REQUIRE,
+ ARG_FULL
};
static const struct option options[] = {
{ "type", required_argument, NULL, 't' },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
+ { "full", no_argument, NULL, ARG_FULL },
{ "fail", no_argument, NULL, ARG_FAIL },
{ "session", no_argument, NULL, ARG_SESSION },
{ "system", no_argument, NULL, ARG_SYSTEM },
arg_dot = DOT_REQUIRE;
break;
+ case ARG_FULL:
+ arg_full = true;
+ break;
+
case 'q':
arg_quiet = true;
break;
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special },
+ { "reset-maintenance", MORE, 1, reset_maintenance },
};
int left;