manager.c revision 0851062751fe5083326308b9901527fc4b234919
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2010 Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* Initial delay and the interval for printing status messages about running jobs */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar/* Where clients shall send notification messages to */
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic int manager_watch_jobs_in_progress(Manager *m) {
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar return sd_event_add_monotonic(m->event, &m->jobs_in_progress_event_source, next, 0, manager_dispatch_jobs_in_progress, m);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletarstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
a34286684ebb78dd3db0d7f34feb2c121c9d00ccMichal Sekletar assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid manager_flip_auto_status(Manager *m, bool enable) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (m->show_status == SHOW_STATUS_TEMPORARY)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_set_show_status(m, SHOW_STATUS_AUTO);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void manager_print_jobs_in_progress(Manager *m) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers if (j->state == JOB_RUNNING && counter++ == print_nr)
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers /* m->n_running_jobs must be consistent with the contents of m->jobs,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * so the above loop must have succeeded in finding j. */
6046278f405b3ebaf84fcf17f6e834c4c4bd6a42Djalal Harouni draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (job_get_timeout(j, &x) > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers "%sA %s job is running for %s (%s / %s)",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_watch_idle_pipe(Manager *m) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0) {
94676f3e9352cbf1f72e0a512ee0d2ed83ff676dLennart Poettering log_error("Failed to watch idle pipe: %s", strerror(-r));
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversstatic void manager_close_idle_pipe(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_setup_time_change(Manager *m) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* We only care for the cancellation event, hence we set the
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna * timeout to the latest possible value. */
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Failed to create timerfd: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Failed to create time change event source: %s", strerror(-r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int enable_special_signals(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Enable that we get SIGINT on control-alt-del. In containers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers * this will fail with EPERM (older) or EINVAL (newer), so
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering * ignore that. */
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering log_warning("Failed to enable ctrl-alt-del handling: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Support systems without virtual console */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning("Failed to open /dev/tty0: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Enable that we get SIGWINCH on kbrequest */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning("Failed to enable kbrequest handling: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_setup_signals(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* We are not interested in SIGSTOP and friends. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek SIGHUP, /* Reload configuration */
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGINT, /* Kernel sends us this on control-alt-del */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+0, /* systemd: start default.target */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+1, /* systemd: isolate rescue.target */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+2, /* systemd: isolate emergency.target */
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer SIGRTMIN+4, /* systemd: start poweroff.target */
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek SIGRTMIN+5, /* systemd: start reboot.target */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+6, /* systemd: start kexec.target */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+14, /* systemd: Immediate poweroff */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+15, /* systemd: Immediate reboot */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+16, /* systemd: Immediate kexec */
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek SIGRTMIN+20, /* systemd: enable status messages */
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek SIGRTMIN+21, /* systemd: disable status messages */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+27, /* systemd: set log target to console */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+28, /* systemd: set log target to kmsg */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m);
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen /* Process signals a bit earlier than the rest of things, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * later that notify_fd processing, so that the notify
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * processing can still figure out to which process/service a
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * message belongs, before we reap the process. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_source_set_priority(m->signal_event_source, -5);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void manager_clean_environment(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Let's remove some environment variables that we
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * need ourselves to communicate with our clients */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "NOTIFY_SOCKET",
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt "MANAGERPID",
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering "WATCHDOG_PID",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "WATCHDOG_USEC",
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversstatic int manager_default_environment(Manager *m) {
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering /* The system manager always starts with a clean
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering * environment for its children. It does not import
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering * the kernel or the parents exported variables.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * The initial passed environ is untouched to keep
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * /proc/self/environ valid; it is used for tagging
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers * the init process inside containers. */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m->environment = strv_new("PATH=" DEFAULT_PATH,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Import locale variables LC_*= from configuration */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* The user manager passes its own environment
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * along to its children. */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringint manager_new(SystemdRunningAs running_as, Manager **_m) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m->exit_code = _MANAGER_EXIT_CODE_INVALID;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering 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;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = hashmap_ensure_allocated(&m->units, string_hash_func, string_compare_func);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = hashmap_ensure_allocated(&m->jobs, trivial_hash_func, trivial_compare_func);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = hashmap_ensure_allocated(&m->cgroup_unit, string_hash_func, string_compare_func);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = set_ensure_allocated(&m->failed_units, trivial_hash_func, trivial_compare_func);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Note that we set up neither kdbus, nor the notify fd
82c1d8f4eb74ddd9be2c9b9b56d9dc564c599effLennart Poettering * here. We do that after deserialization, since they might
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * have gotten serialized across the reexec. */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int manager_setup_notify(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* First free all secondary fields */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->notify_event_source = sd_event_source_unref(m->notify_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Failed to allocate notification socket: %m");
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (getpid() != 1 || detect_container(NULL) > 0)
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%" PRIx64, random_u64());
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek m->notify_socket = strdup(sa.un.sun_path);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Using notification socket %s", m->notify_socket);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Failed to allocate notify event source: %s", strerror(-r));
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen /* Process signals a bit earlier than SIGCHLD, so that we can
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen * still identify to which service an exit message belongs */
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = sd_event_source_set_priority(m->notify_event_source, -7);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers log_error("Failed to set priority of notify event source: %s", strerror(-r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_setup_kdbus(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->kdbus_fd = bus_kernel_create_bus(m->running_as == SYSTEMD_SYSTEM ? "system" : "user", m->running_as == SYSTEMD_SYSTEM, &p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Failed to set up kdbus: %s", strerror(-m->kdbus_fd));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Successfully set up kdbus on %s", p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Create the namespace directory here, so that the contents
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers * of that directory is not visible to non-root users. This is
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * necessary to ensure that users cannot get access to busses
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * of virtualized users when no UID namespacing is used. */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering mkdir_p_label("/dev/kdbus/domain", 0700);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int manager_connect_bus(Manager *m, bool reexecuting) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Try to connect to the busses, if possible. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic unsigned manager_dispatch_cleanup_queue(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned n = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while ((u = m->cleanup_queue)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering GC_OFFSET_GOOD, /* We still need this unit */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering GC_OFFSET_BAD, /* We don't need this unit anymore */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void unit_gc_sweep(Unit *u, unsigned gc_marker) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->gc_marker == gc_marker + GC_OFFSET_BAD ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering /* We were unable to find anything out about this entry, so
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * let's investigate it later */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->gc_marker = gc_marker + GC_OFFSET_UNSURE;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* We definitely know that this one is not useful anymore, so
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * let's mark it for deletion */
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering u->gc_marker = gc_marker + GC_OFFSET_GOOD;
Unit *u;
unsigned gc_marker;
assert(m);
while ((u = m->gc_queue)) {
u->in_gc_queue = false;
m->n_in_gc_queue = 0;
Unit *u;
assert(m);
unit_free(u);
m->n_on_console = 0;
m->n_running_jobs = 0;
UnitType c;
assert(m);
for (c = 0; c < _UNIT_TYPE_MAX; c++)
bus_done(m);
if (m->signal_fd >= 0)
if (m->notify_fd >= 0)
if (m->time_change_fd >= 0)
if (m->kdbus_fd >= 0)
for (i = 0; i < _RLIMIT_MAX; i++)
free(m);
UnitType c;
assert(m);
for (c = 0; c < _UNIT_TYPE_MAX; c++)
Iterator i;
Unit *u;
assert(m);
if (u->id != k)
q = unit_coldplug(u);
assert(m);
if (!m->unit_path_cache) {
d = opendir(*i);
r = -ENOMEM;
goto fail;
goto fail;
closedir(d);
d = NULL;
fail:
Unit *u;
Iterator i;
assert(m);
assert(m);
r = lookup_paths_init(
if (serialization)
m->n_reloading ++;
r = manager_enumerate(m);
if (serialization) {
q = manager_coldplug(m);
if (serialization) {
m->n_reloading --;
m->send_reloading_done = true;
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
assert(m);
return -EINVAL;
return -EPERM;
if (!tr)
return -ENOMEM;
goto tr_abort;
goto tr_abort;
goto tr_abort;
if (_ret)
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
assert(m);
assert(m);
assert(m);
Unit *u;
assert(m);
if (m->dispatching_load_queue)
m->dispatching_load_queue = true;
while ((u = m->load_queue)) {
unit_load(u);
m->dispatching_load_queue = false;
Manager *m,
const char *name,
const char *path,
sd_bus_error *e,
UnitType t;
assert(m);
if (!name)
if (ret) {
if (!ret)
return -ENOMEM;
if (path) {
return -ENOMEM;
if (_ret)
int manager_load_unit(
Manager *m,
const char *name,
const char *path,
sd_bus_error *e,
assert(m);
if (_ret)
Iterator i;
Job *j;
assert(s);
assert(f);
Iterator i;
Unit *u;
assert(s);
assert(f);
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)
assert(m);
assert(u);
assert(n > 0);
if (!tags) {
log_oom();
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
ssize_t n;
assert(m);
bool found = false;
} control = {};
Unit *u;
return -EIO;
return -errno;
buf[n] = 0;
found = true;
found = true;
found = true;
if (!found)
assert(m);
assert(u);
assert(m);
return -errno;
Unit *u;
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;
&sfsi);
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)) {
if (fflush(f)) {
case SIGHUP:
static const char * const target_table[] = {
[0] = SPECIAL_DEFAULT_TARGET,
[0] = MANAGER_HALT,
if (sigchld)
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)
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) {
log_oom();
errno = 0;
Manager *m,
const char *name,
const char* old_owner,
const char *new_owner) {
Unit *u;
assert(m);
const char *path;
FILE *f;
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->notify_fd >= 0) {
int copy;
if (copy < 0)
return copy;
if (m->kdbus_fd >= 0) {
int copy;
if (copy < 0)
return copy;
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->notify_fd >= 0) {
r = -ENOMEM;
goto finish;
m->notify_socket = n;
int fd;
if (m->kdbus_fd >= 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_setup_notify(m);
q = manager_coldplug(m);
m->n_reloading--;
m->send_reloading_done = true;
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) {
manager_flip_auto_status(m, false);
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);
const char *s = NULL;
return -EINVAL;
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);
m->environment = l;
assert(m);
for (i = 0; i < _RLIMIT_MAX; i++) {
if (!default_rlimit[i])
if (!m->rlimit[i])
return -ENOMEM;
Unit *u;
assert(m);
log_open();
assert(m);
if (mode > 0)
assert(m);
if (m->no_console_output)
if (m->show_status > 0)
return plymouth_running();
void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) {
if (!manager_get_show_status(m))
assert(m);
return -ENOMEM;
if (!found) {
assert(m);
assert(m);
Unit *u;
assert(m);
return MANAGER_STARTING;
if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))
return MANAGER_STOPPING;
return MANAGER_MAINTENANCE;
return MANAGER_MAINTENANCE;
return MANAGER_DEGRADED;
return MANAGER_RUNNING;