manager.c revision 9a636ed8096fa44927f182ac3eaef4104866d4a9
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright 2010 Lennart Poettering
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer systemd is free software; you can redistribute it and/or modify it
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer under the terms of the GNU Lesser General Public License as published by
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier the Free Software Foundation; either version 2.1 of the License, or
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier (at your option) any later version.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier systemd is distributed in the hope that it will be useful, but
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier WITHOUT ANY WARRANTY; without even the implied warranty of
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier Lesser General Public License for more details.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier You should have received a copy of the GNU Lesser General Public License
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier/* Initial delay and the interval for printing status messages about running jobs */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier/* Where clients shall send notification messages to */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_setup_notify(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to allocate notification socket: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (getpid() != 1 || detect_container(NULL) > 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = bind(m->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_event_add_io(m->event, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m, &m->notify_event_source);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to allocate notify event source: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Using notification socket %s", m->notify_socket);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_watch_jobs_in_progress(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return sd_event_add_monotonic(m->event, JOBS_IN_PROGRESS_WAIT_SEC, 0, manager_dispatch_jobs_in_progress, m, &m->jobs_in_progress_event_source);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void manager_print_jobs_in_progress(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (j->state == JOB_RUNNING && counter++ == print_nr)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* m->n_running_jobs must be consistent with the contents of m->jobs,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * so the above loop must have succeeded in finding j. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier cylon_pos = m->jobs_in_progress_iteration % 14;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier manager_status_printf(m, true, cylon, "%sA %s job is running for %s",
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier strempty(job_of_n), job_type_to_string(j->type), unit_description(j->unit));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_watch_idle_pipe(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_event_add_io(m->event, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m, &m->idle_pipe_event_source);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to watch idle pipe: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void manager_close_idle_pipe(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_setup_time_change(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* We only care for the cancellation event, hence we set the
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * timeout to the latest possible value. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = sd_event_add_io(m->event, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m, &m->time_change_event_source);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to create time change event source: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int enable_special_signals(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Enable that we get SIGINT on control-alt-del. In containers
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * this will fail with EPERM (older) or EINVAL (newer), so
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * ignore that. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to enable ctrl-alt-del handling: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Support systems without virtual console */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to open /dev/tty0: %m");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Enable that we get SIGWINCH on kbrequest */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to enable kbrequest handling: %m");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We are not interested in SIGSTOP and friends. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGINT, /* Kernel sends us this on control-alt-del */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+0, /* systemd: start default.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+1, /* systemd: isolate rescue.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+2, /* systemd: isolate emergency.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+4, /* systemd: start poweroff.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+20, /* systemd: enable status messages */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+21, /* systemd: disable status messages */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+27, /* systemd: set log target to console */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+28, /* systemd: set log target to kmsg */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = sd_event_add_io(m->event, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m, &m->signal_event_source);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Process signals a bit earlier than the rest of things */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = sd_event_source_set_priority(m->signal_event_source, -5);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int manager_default_environment(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* The system manager always starts with a clean
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * environment for its children. It does not import
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * the kernel or the parents exported variables.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * The initial passed environ is untouched to keep
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * /proc/self/environ valid; it is used for tagging
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * the init process inside containers. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->environment = strv_new("PATH=" DEFAULT_PATH,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Import locale variables LC_*= from configuration */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* The user manager passes its own environment
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * along to its children. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* If there's already a bus address set, don't set up kdbus */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->kdbus_fd = bus_kernel_create_bus(m->running_as == SYSTEMD_SYSTEM ? "system" : "user", &p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->kdbus_fd < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_debug("Failed to set up kdbus: %s", strerror(-m->kdbus_fd));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_debug("Successfully set up kdbus on %s", p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int manager_connect_bus(Manager *m, bool reexecuting) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Try to connect to the busses, if possible. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_new(SystemdRunningAs running_as, Manager **_m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = -1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_ensure_allocated(&m->units, string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_ensure_allocated(&m->jobs, trivial_hash_func, trivial_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_ensure_allocated(&m->cgroup_unit, string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_ensure_allocated(&m->watch_pids, trivial_hash_func, trivial_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = sd_event_add_defer(m->event, manager_dispatch_run_queue, m, &m->run_queue_event_source);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic unsigned manager_dispatch_cleanup_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->cleanup_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_BAD, /* We don't need this unit anymore */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void unit_gc_sweep(Unit *u, unsigned gc_marker) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We were unable to find anything out about this entry, so
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * let's investigate it later */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We definitely know that this one is not useful anymore, so
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * let's mark it for deletion */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic unsigned manager_dispatch_gc_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* log_debug("Running GC..."); */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->gc_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void manager_clear_jobs_and_units(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (c = 0; c < _UNIT_TYPE_MAX; c++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* If we reexecute ourselves, we keep the root cgroup
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(m->time_change_event_source);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(m->jobs_in_progress_event_source);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(m->idle_pipe_event_source);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(m->run_queue_event_source);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (i = 0; i < RLIMIT_NLIMITS; i++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(hashmap_isempty(m->units_requiring_mounts_for));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Let's ask every type to load all units from disk/kernel
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * that it might know */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (c = 0; c < _UNIT_TYPE_MAX; c++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Then, let's set up their initial state. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* ignore aliases */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->id != k)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((q = unit_coldplug(u)) < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void manager_build_unit_path_cache(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->unit_path_cache = set_new(string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to allocate unit path cache.");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* This simply builds a list of files we know exist, so that
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * we don't always have to go to disk */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to open directory %s: %m", *i);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to build unit path cache: %s", strerror(-r));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int manager_distribute_fds(Manager *m, FDSet *fds) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dual_timestamp_get(&m->generators_start_timestamp);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dual_timestamp_get(&m->generators_finish_timestamp);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* If we will deserialize make sure that during enumeration
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * this is already known, so we increase the counter here
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * already */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* First, enumerate what we can from all config files */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dual_timestamp_get(&m->units_load_start_timestamp);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dual_timestamp_get(&m->units_load_finish_timestamp);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Second, deserialize if there is something to deserialize */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer q = manager_deserialize(m, serialization, fds);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Any fds left? Find some unit which wants them. This is
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * useful to allow container managers to pass some file
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * descriptors to us pre-initialized. This enables
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * socket-based activation of entire containers. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* We might have deserialized the kdbus control fd, but if we
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * didn't, then let's create the bus now. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Third, fire things up! */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Let's wait for the UnitNew/JobNew messages being
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * sent, before we notify that the reload is
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * finished */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (mode == JOB_ISOLATE && type != JOB_START) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (mode == JOB_ISOLATE && !unit->allow_isolate) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_to_string(type), job_mode_to_string(mode));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_to_string(type), (unsigned) tr->anchor_job->id);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = manager_load_unit(m, name, NULL, NULL, &unit);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return manager_add_job(m, type, unit, mode, override, e, _ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return hashmap_get(m->jobs, UINT32_TO_PTR(id));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald HoyerUnit *manager_get_unit(Manager *m, const char *name) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerunsigned manager_dispatch_load_queue(Manager *m) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unsigned n = 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Make sure we are not run recursively */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Dispatches the load queue. Takes a unit from the queue and
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * tries to load its data until the queue is empty */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer while ((u = m->load_queue)) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *name,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *path,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* This will prepare the unit for loading, but not actually
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * load anything from disk. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer ret = unit_new(m, unit_vtable[t]->object_size);
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *name,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *path,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* This will load the service information files, but not actually
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * start any services or anything. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_load_unit_prepare(m, name, path, e, _ret);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyervoid manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyervoid manager_dump_units(Manager *s, FILE *f, const char *prefix) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->id == t)
Job *j;
assert(m);
Job *j;
assert(m);
while ((j = m->run_queue)) {
if (m->n_running_jobs > 0)
if (m->n_on_console > 0)
Job *j;
Unit *u;
assert(m);
if (m->dispatching_dbus_queue)
m->dispatching_dbus_queue = true;
while ((u = m->dbus_unit_queue)) {
while ((j = m->dbus_job_queue)) {
m->dispatching_dbus_queue = false;
if (m->send_reloading_done) {
m->send_reloading_done = false;
bus_manager_send_reloading(m, false);
if (m->queued_message)
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
ssize_t n;
assert(m);
} control = {};
Unit *u;
return -EIO;
return -errno;
buf[n] = 0;
if (!tags)
return log_oom();
assert(m);
Unit *u;
return -errno;
return -errno;
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
ssize_t n;
bool sigchld = false;
assert(m);
if (n != sizeof(sfsi)) {
return -EIO;
return -errno;
char *p = NULL;
free(p);
case SIGCHLD:
sigchld = true;
case SIGTERM:
case SIGINT:
case SIGWINCH:
case SIGPWR:
case SIGUSR1: {
Unit *u;
bus_init(m, true);
case SIGUSR2: {
if (ferror(f)) {
case SIGHUP:
static const char * const target_table[] = {
[0] = SPECIAL_DEFAULT_TARGET,
[0] = MANAGER_HALT,
manager_set_show_status(m, true);
manager_set_show_status(m, false);
if (sigchld)
return manager_dispatch_sigchld(m);
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Iterator i;
Unit *u;
assert(m);
NULL);
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
assert(m);
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) {
assert(m);
assert(m);
r = manager_dispatch_sigchld(m);
if (manager_dispatch_load_queue(m) > 0)
if (manager_dispatch_gc_queue(m) > 0)
if (manager_dispatch_cleanup_queue(m) > 0)
if (manager_dispatch_cgroup_queue(m) > 0)
if (manager_dispatch_dbus_queue(m) > 0)
if (wait_usec <= 0)
return m->exit_code;
Unit *u;
assert(m);
assert(s);
r = unit_name_from_dbus_path(s, &n);
*_u = u;
unsigned id;
Job *j;
assert(m);
assert(s);
return -EINVAL;
return -ENOENT;
*_j = j;
#ifdef HAVE_AUDIT
int audit_fd;
if (audit_fd < 0)
if (m->n_reloading > 0)
free(p);
if (m->n_reloading > 0)
if (fd < 0) {
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
goto finish;
log_oom();
goto finish;
errno = 0;
goto finish;
if (fd >= 0)
Manager *m,
const char *name,
const char* old_owner,
const char *new_owner) {
Unit *u;
assert(m);
FILE *f;
if (!path)
return -ENOMEM;
if (fd < 0) {
return -errno;
return -errno;
*_f = f;
Iterator i;
Unit *u;
assert(m);
assert(f);
m->n_reloading ++;
if (!in_initrd()) {
if (!switching_root) {
if (!ce)
return -ENOMEM;
if (m->kdbus_fd >= 0) {
int copy;
if (copy < 0)
return copy;
bus_serialize(m, f);
if (u->id != t)
if (!unit_can_serialize(u))
m->n_reloading --;
m->n_reloading --;
if (ferror(f))
return -EIO;
assert(m);
assert(f);
m->n_reloading ++;
if (feof(f))
r = -errno;
goto finish;
uint32_t n;
m->n_installed_jobs += n;
uint32_t n;
m->n_failed_jobs += n;
if (!uce) {
r = -ENOMEM;
goto finish;
r = -ENOMEM;
goto finish;
m->environment = e;
int fd;
if (m->kdbus_fd >= 0)
} else if (bus_deserialize_item(m, l) == 0)
Unit *u;
if (feof(f))
r = -errno;
goto finish;
goto finish;
goto finish;
if (ferror(f))
r = -EIO;
m->n_reloading --;
assert(m);
r = manager_open_serialization(m, &f);
m->n_reloading ++;
bus_manager_send_reloading(m, true);
if (!fds) {
m->n_reloading --;
return -ENOMEM;
m->n_reloading --;
m->n_reloading --;
return -errno;
q = lookup_paths_init(
q = manager_enumerate(m);
fclose(f);
f = NULL;
q = manager_coldplug(m);
m->n_reloading--;
m->send_reloading_done = true;
Unit *u;
assert(m);
return !!u->job;
assert(m);
return m->n_reloading != 0;
Unit *u;
Iterator i;
assert(m);
Unit *u;
assert(m);
return unit_inactive_or_pending(u);
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
assert(m);
if (m->n_running_jobs == 0)
if (m->jobs_in_progress_event_source)
m->confirm_spawn = false;
if (!log_on_console())
NULL);
initrd_usec = 0;
if (!log_on_console())
NULL);
if (!log_on_console())
NULL);
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
sd_notifyf(false,
assert(m);
if (*generator)
return log_oom();
p, strerror(-r));
free(p);
return log_oom();
if (!mkdtemp(p)) {
free(p);
return -errno;
*generator = p;
assert(m);
if (!*generator)
const char *generator_path;
assert(m);
goto finish;
goto finish;
goto finish;
assert(m);
if (!*generator)
assert(m);
assert(m);
l = m->environment;
return -ENOMEM;
return -ENOMEM;
if (m->environment != l)
strv_free(a);
strv_free(b);
assert(m);
for (i = 0; i < RLIMIT_NLIMITS; i++) {
if (!default_rlimit[i])
if (!m->rlimit[i])
return -ENOMEM;
Unit *u;
assert(m);
log_open();
assert(m);
m->show_status = b;
assert(m);
if (m->no_console_output)
if (m->show_status)
return plymouth_running();
void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) {
if (!manager_get_show_status(m))
if (!manager_is_booting_or_shutting_down(m))
assert(m);
return -ENOMEM;
if (!found) {
assert(m);