DOT_ORDER,
DOT_REQUIRE
} arg_dot = DOT_ALL;
+static enum transport {
+ TRANSPORT_NORMAL,
+ TRANSPORT_SSH,
+ TRANSPORT_POLKIT
+} arg_transport = TRANSPORT_NORMAL;
+static const char *arg_host = NULL;
static bool private_bus = false;
if (on_tty()) {
printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
- if (columns() >= 80+12 || arg_full)
+ if (columns() >= 80+12 || arg_full || !arg_no_pager)
printf(" %s\n", "DESCRIPTION");
else
printf("\n");
if (u->job_id == 0)
printf(" %-*s", job_len, "");
- if (arg_full)
+ if (arg_full || !arg_no_pager)
printf(" %s", u->description);
else
printf(" %.*s", columns() - a - b - 1, u->description);
log_error("Job canceled.");
else if (streq(d.result, "dependency"))
log_error("A dependency job failed. See system logs for details.");
- else if (!streq(d.result, "done"))
+ else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
log_error("Job failed. See system logs and 'systemctl status' for details.");
}
r = -ETIME;
else if (streq_ptr(d.result, "canceled"))
r = -ECANCELED;
- else if (!streq_ptr(d.result, "done"))
+ else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
r = -EIO;
else
r = 0;
if (arg_action == ACTION_SYSTEMCTL) {
method =
- streq(args[0], "stop") ? "StopUnit" :
+ streq(args[0], "stop") ||
+ streq(args[0], "condstop") ? "StopUnit" :
streq(args[0], "reload") ? "ReloadUnit" :
streq(args[0], "restart") ? "RestartUnit" :
+
streq(args[0], "try-restart") ||
streq(args[0], "condrestart") ? "TryRestartUnit" :
+
streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
+
streq(args[0], "reload-or-try-restart") ||
streq(args[0], "condreload") ||
+
streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
"StartUnit";
dbus_error_free(&error);
dbus_message_unref(m);
+ m = NULL;
continue;
}
}
static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
- uint64_t start_timestamp, exit_timestamp;
+ uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
DBusMessageIter sub2, sub3;
const char*path;
unsigned n;
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, &start_timestamp_monotonic, 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_UINT64, &exit_timestamp_monotonic, 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, &code, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
int exit_code, exit_status;
+ usec_t condition_timestamp;
+ bool condition_result;
+
/* Socket */
unsigned n_accepted;
unsigned n_connections;
else
printf("\n");
+ if (!i->condition_result && i->condition_timestamp > 0) {
+ s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
+ s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
+
+ if (s1)
+ printf("\t start condition failed at %s; %s\n", s2, s1);
+ else if (s2)
+ printf("\t start condition failed at %s\n", s2);
+ }
+
if (i->sysfs_path)
printf("\t Device: %s\n", i->sysfs_path);
if (i->where)
printf("\t CGroup: %s\n", i->default_control_group);
- if ((c = columns()) > 18)
- c -= 18;
- else
- c = 0;
+ if (arg_transport != TRANSPORT_SSH) {
+ if ((c = columns()) > 18)
+ c -= 18;
+ else
+ c = 0;
- show_cgroup_by_path(i->default_control_group, "\t\t ", c);
+ show_cgroup_by_path(i->default_control_group, "\t\t ", c);
+ }
}
if (i->need_daemon_reload)
i->accept = b;
else if (streq(name, "NeedDaemonReload"))
i->need_daemon_reload = b;
+ else if (streq(name, "ConditionResult"))
+ i->condition_result = b;
break;
}
i->inactive_exit_timestamp = (usec_t) u;
else if (streq(name, "ActiveExitTimestamp"))
i->active_exit_timestamp = (usec_t) u;
+ else if (streq(name, "ConditionTimestamp"))
+ i->condition_timestamp = (usec_t) u;
break;
}
/* Yes, heuristics! But we can change this check
* should it turn out to not be sufficient */
- if (strstr(name, "Timestamp")) {
+ if (endswith(name, "Timestamp")) {
char timestamp[FORMAT_TIMESTAMP_MAX], *t;
if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
return 0;
+ } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
+ DBusMessageIter sub, sub2;
+
+ dbus_message_iter_recurse(iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+ const char *path;
+ dbus_bool_t ignore;
+
+ dbus_message_iter_recurse(&sub, &sub2);
+
+ if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
+ bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
+ printf("EnvironmentFile=%s (ignore=%s)\n", path, yes_no(ignore));
+
+ dbus_message_iter_next(&sub);
+ }
+
+ return 0;
+
} else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
DBusMessageIter sub, sub2;
else
printf("Unit %s removed.\n", id);
- } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
- dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
+ } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew")) {
+ uint32_t id;
+ const char *path;
+
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ log_error("Failed to parse message: %s", bus_error_message(&error));
+ else
+ printf("Job %u added.\n", id);
+
+
+ } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
const char *path, *result;
DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID))
log_error("Failed to parse message: %s", bus_error_message(&error));
- else if (streq(dbus_message_get_member(message), "JobNew"))
- printf("Job %u added.\n", id);
else
- printf("Job %u removed.\n", id);
+ printf("Job %u removed (result=%s).\n", id, result);
} else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
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;
+ }
+
log_error("Failed to issue method call: %s", bus_error_message(&error));
r = -EIO;
goto finish;
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
return 1;
}
+ free(dest);
return 0;
}
static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo *i, const char *config_path) {
const ConfigItem items[] = {
- { "Alias", config_parse_strv, &i->aliases, "Install" },
- { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
- { "Also", config_parse_also, NULL, "Install" },
+ { "Alias", config_parse_strv, 0, &i->aliases, "Install" },
+ { "WantedBy", config_parse_strv, 0, &i->wanted_by, "Install" },
+ { "Also", config_parse_also, 0, NULL, "Install" },
- { NULL, NULL, NULL, NULL }
+ { NULL, NULL, 0, NULL, NULL }
};
char **p;
}
if (!f) {
-#if defined(TARGET_FEDORA) && defined (HAVE_SYSV_COMPAT)
+#if (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX)) && defined (HAVE_SYSV_COMPAT)
if (endswith(i->name, ".service")) {
char *sysv;
argv[1] = file_name_from_path(sysv);
argv[2] =
streq(verb, "enable") ? "on" :
- streq(verb, "disable") ? "off" : NULL;
+ streq(verb, "disable") ? "off" : "--level=5";
log_info("Executing %s %s %s", argv[0], argv[1], strempty(argv[2]));
return r;
if (status.si_code == CLD_EXITED) {
- if (status.si_status == 0 && (streq(verb, "enable") || streq(verb, "disable")))
+
+ if (streq(verb, "is-enabled"))
+ return status.si_status == 0 ? 1 : 0;
+
+ if (status.si_status == 0)
n_symlinks ++;
return status.si_status == 0 ? 0 : -EINVAL;
+
} else
return -EPROTO;
}
return r;
}
+ /* Consider unit files stored in /lib and /usr always enabled
+ * if they have no [Install] data. */
+ if (streq(verb, "is-enabled") &&
+ strv_isempty(i->aliases) &&
+ strv_isempty(i->wanted_by) &&
+ !path_startswith(filename, "/etc")) {
+ fclose(f);
+ return 1;
+ }
+
n_symlinks += strv_length(i->aliases);
n_symlinks += strv_length(i->wanted_by);
goto finish;
}
+ r = 0;
+
while ((i = hashmap_first(will_install))) {
int q;
" pending\n"
" --ignore-dependencies\n"
" When queueing a new job, ignore all its dependencies\n"
+ " --kill-mode=MODE How to send signal\n"
+ " --kill-who=WHO Who to send signal to\n"
+ " -s --signal=SIGNAL Which signal to send\n"
+ " -H --host=[user@]host\n"
+ " Show information for remote host\n"
+ " -P --privileged Acquire privileges before execution\n"
" -q --quiet Suppress output\n"
" --no-block Do not wait until operation finished\n"
- " --no-pager Do not pipe output into a pager.\n"
- " --system Connect to system manager\n"
- " --user Connect to user service manager\n"
- " --order When generating graph for dot, show only order\n"
- " --require When generating graph for dot, show only requirement\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
- " --global Enable/disable unit files globally\n"
" --no-reload When enabling/disabling unit files, don't reload daemon\n"
" configuration\n"
+ " --no-pager Do not pipe output into a pager.\n"
" --no-ask-password\n"
" Do not ask for system passwords\n"
- " --kill-mode=MODE How to send signal\n"
- " --kill-who=WHO Who to send signal to\n"
- " -s --signal=SIGNAL Which signal to send\n"
+ " --order When generating graph for dot, show only order\n"
+ " --require When generating graph for dot, show only requirement\n"
+ " --system Connect to system manager\n"
+ " --user Connect to user service manager\n"
+ " --global Enable/disable unit files globally\n"
" -f --force When enabling unit files, override existing symlinks\n"
" When shutting down, execute action immediately\n"
" --defaults When disabling unit files, remove default symlinks only\n\n"
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
{ "signal", required_argument, NULL, 's' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
+ { "host", required_argument, NULL, 'H' },
+ { "privileged",no_argument, NULL, 'P' },
{ NULL, 0, NULL, 0 }
};
/* Only when running as systemctl we ask for passwords */
arg_ask_password = true;
- while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:P", options, NULL)) >= 0) {
switch (c) {
arg_ask_password = false;
break;
+ case 'P':
+ arg_transport = TRANSPORT_POLKIT;
+ break;
+
+ case 'H':
+ arg_transport = TRANSPORT_SSH;
+ arg_host = optarg;
+ break;
+
case '?':
return -EINVAL;
}
}
+ if (arg_transport != TRANSPORT_NORMAL && arg_user) {
+ log_error("Cannot access user instance remotely.");
+ return -EINVAL;
+ }
+
return 1;
}
{ "cancel", MORE, 2, cancel_job },
{ "start", MORE, 2, start_unit },
{ "stop", MORE, 2, start_unit },
+ { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
{ "reload", MORE, 2, start_unit },
{ "restart", MORE, 2, start_unit },
{ "try-restart", MORE, 2, start_unit },
/* Require a bus connection for all operations but
* enable/disable */
- if (!streq(verbs[i].verb, "enable") &&
- !streq(verbs[i].verb, "disable") &&
- !bus) {
- log_error("Failed to get D-Bus connection: %s", error->message);
- return -EIO;
+ if (!streq(verbs[i].verb, "enable") && !streq(verbs[i].verb, "disable")) {
+
+ if (running_in_chroot() > 0) {
+ log_info("Running in chroot, ignoring request.");
+ return 0;
+ }
+
+ if (!bus) {
+ log_error("Failed to get D-Bus connection: %s", error->message);
+ return -EIO;
+ }
}
return verbs[i].dispatch(bus, argv + optind, left);
zero(sockaddr);
sockaddr.sa.sa_family = AF_UNIX;
sockaddr.un.sun_path[0] = 0;
- strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
+ strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
zero(iovec);
iovec.iov_base = (char*) &c;
zero(msghdr);
msghdr.msg_name = &sockaddr;
- msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
+ msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
msghdr.msg_iov = &iovec;
msghdr.msg_iovlen = 1;
if (!on_tty() || arg_no_pager)
return;
- if ((pager = getenv("PAGER")))
+ if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
if (!*pager || streq(pager, "cat"))
return;
goto finish;
}
- bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
+ if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
+ log_info("Running in chroot, ignoring request.");
+ retval = 0;
+ goto finish;
+ }
+
+ if (arg_transport == TRANSPORT_NORMAL)
+ bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
+ else if (arg_transport == TRANSPORT_POLKIT) {
+ bus_connect_system_polkit(&bus, &error);
+ private_bus = false;
+ } else if (arg_transport == TRANSPORT_SSH) {
+ bus_connect_system_ssh(NULL, arg_host, &bus, &error);
+ private_bus = false;
+ } else
+ assert_not_reached("Uh, invalid transport...");
switch (arg_action) {