static bool private_bus = false;
static pid_t pager_pid = 0;
+static pid_t agent_pid = 0;
static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
static void pager_open(void);
}
static void spawn_ask_password_agent(void) {
- pid_t parent, child;
+ pid_t parent;
+
+ if (agent_pid > 0)
+ return;
/* We check STDIN here, not STDOUT, since this is about input,
* not output */
/* Spawns a temporary TTY agent, making sure it goes away when
* we go away */
- if ((child = fork()) < 0)
+ if ((agent_pid = fork()) < 0)
return;
- if (child == 0) {
+ if (agent_pid == 0) {
/* In the child */
- const char * const args[] = {
- SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
- "--watch",
- NULL
- };
int fd;
bool stdout_is_tty, stderr_is_tty;
close(fd);
}
- execv(args[0], (char **) args);
+ execl(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
+
+ log_error("Unable to execute agent: %m");
_exit(EXIT_FAILURE);
}
}
typedef struct WaitData {
Set *set;
- bool failed;
+ char *result;
} WaitData;
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path;
+ const char *path, *result;
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", bus_error_message(&error));
- else {
+ 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;
+ if ((p = set_remove(d->set, (char*) path)))
+ free(p);
+
+ if (*result)
+ d->result = strdup(result);
+
+ goto finish;
+ }
+#ifndef LEGACY
+ dbus_error_free(&error);
+
+ if (dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_BOOLEAN, &success,
+ DBUS_TYPE_INVALID)) {
+ char *p;
+
+ /* Compatibility with older systemd versions <
+ * 19 during upgrades. This should be dropped
+ * one day */
+
if ((p = set_remove(d->set, (char*) path)))
free(p);
if (!success)
- d->failed = true;
+ d->result = strdup("failed");
+
+ goto finish;
}
+#endif
+
+ log_error("Failed to parse message: %s", bus_error_message(&error));
}
+finish:
dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
zero(d);
d.set = s;
- d.failed = false;
if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
log_error("Failed to add filter.");
dbus_connection_read_write_dispatch(bus, -1))
;
- if (!arg_quiet && d.failed)
- log_error("Job failed. See system logs and 'systemctl status' for details.");
+ if (!arg_quiet && d.result) {
+ if (streq(d.result, "timeout"))
+ log_error("Job timed out.");
+ else if (streq(d.result, "canceled"))
+ 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") && !streq(d.result, "skipped"))
+ log_error("Job failed. See system logs and 'systemctl status' for details.");
+ }
+
+ if (streq_ptr(d.result, "timeout"))
+ r = -ETIME;
+ else if (streq_ptr(d.result, "canceled"))
+ r = -ECANCELED;
+ else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
+ r = -EIO;
+ else
+ r = 0;
- r = d.failed ? -EIO : 0;
+ free(d.result);
finish:
/* This is slightly dirty, since we don't undo the filter registration. */
streq(args[0], "stop") ? "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";
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 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path;
+ const char *path, *result;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_OBJECT_PATH, &path,
+ 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"))
argv[1] = file_name_from_path(sysv);
argv[2] =
streq(verb, "enable") ? "on" :
- streq(verb, "disable") ? "off" : NULL;
+ streq(verb, "disable") ? "off" : "--level=3";
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;
}
goto finish;
}
+ r = 0;
+
while ((i = hashmap_first(will_install))) {
int q;
{ "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 */
+ { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
{ "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
{ "isolate", EQUAL, 2, start_unit },
{ "kill", MORE, 2, kill_unit },
static void pager_open(void) {
int fd[2];
const char *pager;
+ pid_t parent_pid;
if (pager_pid > 0)
return;
return;
}
+ parent_pid = getpid();
+
pager_pid = fork();
if (pager_pid < 0) {
log_error("Failed to fork pager: %m");
setenv("LESS", "FRSX", 0);
- prctl(PR_SET_PDEATHSIG, SIGTERM);
+ /* Make sure the pager goes away when the parent dies */
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+ _exit(EXIT_FAILURE);
+
+ /* Check whether our parent died before we were able
+ * to set the death signal */
+ if (getppid() != parent_pid)
+ _exit(EXIT_SUCCESS);
if (pager) {
execlp(pager, pager, NULL);
/* Inform pager that we are done */
fclose(stdout);
+ kill(pager_pid, SIGCONT);
wait_for_terminate(pager_pid, &dummy);
pager_pid = 0;
}
+static void agent_close(void) {
+ siginfo_t dummy;
+
+ if (agent_pid <= 0)
+ return;
+
+ /* Inform agent that we are done */
+ kill(agent_pid, SIGTERM);
+ kill(agent_pid, SIGCONT);
+ wait_for_terminate(agent_pid, &dummy);
+ agent_pid = 0;
+}
+
int main(int argc, char*argv[]) {
int r, retval = EXIT_FAILURE;
DBusConnection *bus = NULL;
strv_free(arg_property);
pager_close();
+ agent_close();
return retval;
}