#include "dbus-job.h"
#include "dbus-manager.h"
#include "bus-kernel.h"
+#include "time-util.h"
/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
-#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
-
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
if (m->test_run)
return 0;
- /* We are not interested in SIGSTOP and friends. */
assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
- assert_se(sigemptyset(&mask) == 0);
+ /* We make liberal use of realtime signals here. On
+ * Linux/glibc we have 30 of them (with the exception of Linux
+ * on hppa, see below), between SIGRTMIN+0 ... SIGRTMIN+30
+ * (aka SIGRTMAX). */
+ assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask,
SIGCHLD, /* Child died */
SIGTERM, /* Reexecute daemon */
SIGINT, /* Kernel sends us this on control-alt-del */
SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
+
SIGRTMIN+0, /* systemd: start default.target */
SIGRTMIN+1, /* systemd: isolate rescue.target */
SIGRTMIN+2, /* systemd: isolate emergency.target */
SIGRTMIN+4, /* systemd: start poweroff.target */
SIGRTMIN+5, /* systemd: start reboot.target */
SIGRTMIN+6, /* systemd: start kexec.target */
+
+ /* ... space for more special targets ... */
+
SIGRTMIN+13, /* systemd: Immediate halt */
SIGRTMIN+14, /* systemd: Immediate poweroff */
SIGRTMIN+15, /* systemd: Immediate reboot */
SIGRTMIN+16, /* systemd: Immediate kexec */
+
+ /* ... space for more immediate system state changes ... */
+
SIGRTMIN+20, /* systemd: enable status messages */
SIGRTMIN+21, /* systemd: disable status messages */
SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
+
+ /* .. one free signal here ... */
+
+#if !defined(__hppa64__) && !defined(__hppa__)
+ /* Apparently Linux on hppa has fewer RT
+ * signals (SIGRTMAX is SIGRTMIN+25 there),
+ * hence let's not try to make use of them
+ * here. Since these commands are accessible
+ * by different means and only really a safety
+ * net, the missing functionality on hppa
+ * shouldn't matter. */
+
SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
SIGRTMIN+27, /* systemd: set log target to console */
SIGRTMIN+28, /* systemd: set log target to kmsg */
SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg (obsolete)*/
+
+ /* ... one free signal here SIGRTMIN+30 ... */
+#endif
-1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
return r;
/* Process signals a bit earlier than the rest of things, but
- * later that notify_fd processing, so that the notify
+ * later than notify_fd processing, so that the notify
* processing can still figure out to which process/service a
* message belongs, before we reap the process. */
r = sd_event_source_set_priority(m->signal_event_source, -5);
m->running_as = running_as;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
- m->start_timeout_usec = DEFAULT_MANAGER_START_TIMEOUT_USEC;
- m->start_timeout_action = FAILURE_ACTION_REBOOT_FORCE;
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
if (r < 0)
goto fail;
- r = hashmap_ensure_allocated(&m->units, string_hash_func, string_compare_func);
+ r = hashmap_ensure_allocated(&m->units, &string_hash_ops);
if (r < 0)
goto fail;
- r = hashmap_ensure_allocated(&m->jobs, trivial_hash_func, trivial_compare_func);
+ r = hashmap_ensure_allocated(&m->jobs, NULL);
if (r < 0)
goto fail;
- r = hashmap_ensure_allocated(&m->cgroup_unit, string_hash_func, string_compare_func);
+ r = hashmap_ensure_allocated(&m->cgroup_unit, &string_hash_ops);
if (r < 0)
goto fail;
- r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func);
+ r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops);
if (r < 0)
goto fail;
- r = set_ensure_allocated(&m->startup_units, trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&m->startup_units, NULL);
if (r < 0)
goto fail;
- r = set_ensure_allocated(&m->failed_units, trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&m->failed_units, NULL);
if (r < 0)
goto fail;
r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
if (r < 0) {
log_error("bind(%s) failed: %m", sa.un.sun_path);
- return -errno;
+ if (errno == EADDRINUSE) {
+ log_notice("Removing %s socket and trying again.", m->notify_socket);
+ r = unlink(m->notify_socket);
+ if (r < 0) {
+ log_error("Failed to remove %s: %m", m->notify_socket);
+ return -EADDRINUSE;
+ }
+
+ r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ if (r < 0) {
+ log_error("bind(%s) failed: %m", sa.un.sun_path);
+ return -errno;
+ }
+ } else
+ return -errno;
}
r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
manager_close_idle_pipe(m);
- sd_event_source_unref(m->start_timeout_event_source);
- free(m->start_timeout_reboot_arg);
-
udev_unref(m->udev);
sd_event_unref(m->event);
static void manager_build_unit_path_cache(Manager *m) {
char **i;
- _cleanup_free_ DIR *d = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
int r;
assert(m);
set_free_free(m->unit_path_cache);
- m->unit_path_cache = set_new(string_hash_func, string_compare_func);
+ m->unit_path_cache = set_new(&string_hash_ops);
if (!m->unit_path_cache) {
log_error("Failed to allocate unit path cache.");
return;
return 0;
}
-static int on_start_timeout(sd_event_source *s, usec_t usec, void *userdata) {
- Manager *m = userdata;
-
- assert(s);
- assert(m);
-
- m->start_timeout_event_source = sd_event_source_unref(m->start_timeout_event_source);
-
- log_error("Startup timed out.");
-
- failure_action(m, m->start_timeout_action, m->start_timeout_reboot_arg);
- return 0;
-}
-
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
int r, q;
m->send_reloading_done = true;
}
- /* Possibly set up a start timeout */
- if (!dual_timestamp_is_set(&m->finish_timestamp)) {
- m->start_timeout_event_source = sd_event_source_unref(m->start_timeout_event_source);
-
- if (m->start_timeout_usec) {
- r = sd_event_add_time(
- m->event,
- &m->start_timeout_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + m->start_timeout_usec, 0,
- on_start_timeout, m);
- if (r < 0)
- log_error("Failed to add start timeout event: %s", strerror(-r));
- }
- }
-
return r;
}
uint32_t id;
if (safe_atou32(l+15, &id) < 0)
- log_debug("Failed to parse current job id value %s", l+15);
+ log_warning("Failed to parse current job id value %s", l+15);
else
m->current_job_id = MAX(m->current_job_id, id);
uint32_t n;
if (safe_atou32(l+17, &n) < 0)
- log_debug("Failed to parse installed jobs counter %s", l+17);
+ log_warning("Failed to parse installed jobs counter %s", l+17);
else
m->n_installed_jobs += n;
uint32_t n;
if (safe_atou32(l+14, &n) < 0)
- log_debug("Failed to parse failed jobs counter %s", l+14);
+ log_warning("Failed to parse failed jobs counter %s", l+14);
else
m->n_failed_jobs += n;
b = parse_boolean(l+10);
if (b < 0)
- log_debug("Failed to parse taint /usr flag %s", l+10);
+ log_warning("Failed to parse taint /usr flag %s", l+10);
else
m->taint_usr = m->taint_usr || b;
int fd;
if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse notify fd: %s", l + 10);
+ log_warning("Failed to parse notify fd: %s", l + 10);
else {
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
safe_close(m->notify_fd);
int fd;
if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse kdbus fd: %s", l + 9);
+ log_warning("Failed to parse kdbus fd: %s", l + 9);
else {
safe_close(m->kdbus_fd);
m->kdbus_fd = fdset_remove(fds, fd);
}
} else if (bus_track_deserialize_item(&m->deserialized_subscribed, l) == 0)
- log_debug("Unknown serialization item '%s'", l);
+ log_warning("Unknown serialization item '%s'", l);
}
for (;;) {
dual_timestamp_get(&m->finish_timestamp);
- m->start_timeout_event_source = sd_event_source_unref(m->start_timeout_event_source);
-
if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
if (!strv_isempty(plus)) {
b = strv_env_merge(2, l, plus);
- if (!b)
+ if (!b) {
+ strv_free(a);
return -ENOMEM;
+ }
l = b;
}
if (m->no_console_output)
return false;
- if (!IN_SET(manager_state(m), MANAGER_STARTING, MANAGER_STOPPING))
+ if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
return false;
if (m->show_status > 0)
assert(m);
/* Did we ever finish booting? If not then we are still starting up */
- if (!dual_timestamp_is_set(&m->finish_timestamp))
+ if (!dual_timestamp_is_set(&m->finish_timestamp)) {
+
+ u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
+ if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
+ return MANAGER_INITIALIZING;
+
return MANAGER_STARTING;
+ }
/* Is the special shutdown target queued? If so, we are in shutdown state */
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
}
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
+ [MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
[MANAGER_RUNNING] = "running",
[MANAGER_DEGRADED] = "degraded",