manager.c revision df0060346ae326bf3c21140ddb3f0ffa519e2e7f
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek This file is part of systemd.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek Copyright 2010 Lennart Poettering
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek (at your option) any later version.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek/* Initial delay and the interval for printing status messages about running jobs */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic int manager_run_generators(Manager *m);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic void manager_undo_generators(Manager *m);
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poetteringstatic void manager_watch_jobs_in_progress(Manager *m) {
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poettering next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
29a5ca9baa58e55c4d9e1d008cdd014aa9c3c3e1Lennart Poettering (void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED)-1) + sizeof(ANSI_HIGHLIGHT_RED)-1 + 2*(sizeof(ANSI_NORMAL)-1))
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek p = stpcpy(p, ANSI_HIGHLIGHT_RED);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek p = mempset(p, ' ', width-1-pos);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekvoid manager_flip_auto_status(Manager *m, bool enable) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (m->show_status == SHOW_STATUS_AUTO)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (m->show_status == SHOW_STATUS_TEMPORARY)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek manager_set_show_status(m, SHOW_STATUS_AUTO);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic void manager_print_jobs_in_progress(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek char cylon[6 + CYLON_BUFFER_EXTRA + 1];
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (j->state == JOB_RUNNING && counter++ == print_nr)
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek /* m->n_running_jobs must be consistent with the contents of m->jobs,
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek * so the above loop must have succeeded in finding j. */
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek assert(counter == print_nr + 1);
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek cylon_pos = m->jobs_in_progress_iteration % 14;
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek m->jobs_in_progress_iteration++;
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek "%sA %s job is running for %s (%s / %s)",
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic int have_ask_password(void) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek dir = opendir("/run/systemd/ask-password");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (startswith(de->d_name, "ask."))
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic int manager_dispatch_ask_password_fd(sd_event_source *source,
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek int fd, uint32_t revents, void *userdata) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->have_ask_password = have_ask_password();
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* Log error but continue. Negative have_ask_password
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek * is treated as unknown status. */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic void manager_close_ask_password(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic int manager_check_ask_password(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (!m->ask_password_event_source) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert(m->ask_password_inotify_fd < 0);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek mkdir_p_label("/run/systemd/ask-password", 0755);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (m->ask_password_inotify_fd < 0)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return log_error_errno(errno, "inotify_init1() failed: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_error_errno(errno, "Failed to add watch on /run/systemd/ask-password: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = sd_event_add_io(m->event, &m->ask_password_event_source,
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->ask_password_inotify_fd, EPOLLIN,
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek manager_dispatch_ask_password_fd, m);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_error_errno(errno, "Failed to add event source for /run/systemd/ask-password: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek (void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
e9c1ea9de87d4d508ac38ce87a2fa56e7529a91aJason St. John /* Queries might have been added meanwhile... */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek manager_dispatch_ask_password_fd(m->ask_password_event_source,
e9c1ea9de87d4d508ac38ce87a2fa56e7529a91aJason St. Johnstatic int manager_watch_idle_pipe(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to watch idle pipe: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek (void) sd_event_source_set_description(m->idle_pipe_event_source, "manager-idle-pipe");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic void manager_close_idle_pipe(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek safe_close_pair(m->idle_pipe + 2);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic int manager_setup_time_change(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* We only care for the cancellation event, hence we set the
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek * timeout to the latest possible value. */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering return log_error_errno(errno, "Failed to create timerfd: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_debug_errno(errno, "Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek m->time_change_fd = safe_close(m->time_change_fd);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to create time change event source: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek (void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmekstatic int enable_special_signals(Manager *m) {
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek /* Enable that we get SIGINT on control-alt-del. In containers
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek * this will fail with EPERM (older) or EINVAL (newer), so
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek * ignore that. */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* Support systems without virtual console */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_warning_errno(errno, "Failed to open /dev/tty0: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* Enable that we get SIGWINCH on kbrequest */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekstatic int manager_setup_signals(Manager *m) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek .sa_flags = SA_NOCLDSTOP|SA_RESTART,
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* We make liberal use of realtime signals here. On
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek * Linux/glibc we have 30 of them (with the exception of Linux
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek * on hppa, see below), between SIGRTMIN+0 ... SIGRTMIN+30
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek * (aka SIGRTMAX). */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert_se(sigemptyset(&mask) == 0);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGHUP, /* Reload configuration */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGUSR2, /* systemd: dump status */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGINT, /* Kernel sends us this on control-alt-del */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+0, /* systemd: start default.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+1, /* systemd: isolate rescue.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+2, /* systemd: isolate emergency.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+3, /* systemd: start halt.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+4, /* systemd: start poweroff.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+5, /* systemd: start reboot.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+6, /* systemd: start kexec.target */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* ... space for more special targets ... */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+13, /* systemd: Immediate halt */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+14, /* systemd: Immediate poweroff */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+15, /* systemd: Immediate reboot */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+16, /* systemd: Immediate kexec */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* ... space for more immediate system state changes ... */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek SIGRTMIN+20, /* systemd: enable status messages */
if (m->signal_fd < 0)
return -errno;
r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m);
return enable_special_signals(m);
assert(m);
m->environment,
NULL);
assert(m);
NULL);
if (!m->environment)
return -ENOMEM;
Manager *m;
return -ENOMEM;
#ifdef ENABLE_EFI
r = manager_default_environment(m);
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
r = manager_setup_signals(m);
goto fail;
r = manager_setup_cgroup(m);
goto fail;
r = manager_setup_time_change(m);
goto fail;
if (!m->udev) {
r = -ENOMEM;
goto fail;
*_m = m;
fail:
manager_free(m);
if (m->test_run)
if (m->notify_fd < 0) {
if (fd < 0)
return -EINVAL;
if (!m->notify_socket)
return log_oom();
if (!m->notify_event_source) {
r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m);
assert(m);
if (!is_kdbus_available())
return -ESOCKTNOSUPPORT;
if (m->kdbus_fd < 0)
bool try_bus_connect;
assert(m);
if (m->test_run)
m->kdbus_fd >= 0 ||
reexecuting ||
Unit *u;
assert(m);
while ((u = m->cleanup_queue)) {
unit_free(u);
Iterator i;
bool is_bad;
assert(u);
if (u->in_cleanup_queue)
goto bad;
if (unit_check_gc(u))
goto good;
is_bad = true;
goto good;
is_bad = false;
if (is_bad)
goto bad;
bad:
good:
Unit *u;
unsigned gc_marker;
assert(m);
while ((u = m->gc_queue)) {
u->in_gc_queue = false;
if (u->id)
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;
return NULL;
for (c = 0; c < _UNIT_TYPE_MAX; c++)
bus_done(m);
for (i = 0; i < _RLIMIT_MAX; i++)
free(m);
return NULL;
UnitType c;
assert(m);
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
if (!unit_type_supported(c)) {
Iterator i;
Unit *u;
assert(m);
if (u->id != k)
r = unit_coldplug(u);
assert(m);
if (!m->unit_path_cache) {
d = opendir(*i);
r = -ENOMEM;
goto fail;
goto fail;
d = safe_closedir(d);
fail:
Iterator i;
Unit *u;
assert(m);
assert(m);
r = manager_run_generators(m);
r = lookup_paths_init(
NULL,
if (serialization)
m->n_reloading ++;
if (serialization)
q = manager_setup_notify(m);
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 sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
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)
static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
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) {
} control = {};
bool found = false;
unsigned n_fds = 0;
ssize_t n;
assert(m);
return -errno;
if (n_fds > 0) {
return log_oom();
buf[n] = 0;
if (u1) {
found = true;
found = true;
found = true;
if (!found)
assert(m);
assert(u);
assert(m);
return -errno;
if (u1)
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:
status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
case SIGWINCH:
case SIGPWR:
case SIGUSR1: {
Unit *u;
bus_init(m, true);
case SIGUSR2: {
r = fflush_and_check(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
const char *msg;
int audit_fd, r;
if (audit_fd < 0)
if (m->n_reloading > 0)
if (m->n_reloading > 0)
if (detect_container() > 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;
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)
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;
goto finish;
r = -ENOMEM;
goto finish;
m->environment = e;
int fd;
r = -ENOMEM;
goto finish;
m->notify_socket = n;
int fd;
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 = manager_run_generators(m);
q = lookup_paths_init(
NULL,
fclose(f);
f = NULL;
q = manager_setup_notify(m);
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];
if (m->test_run)
NULL);
initrd_usec = 0;
NULL);
NULL);
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
sd_notifyf(false,
assert(m);
if (m->n_reloading > 0)
if (m->jobs_in_progress_event_source)
(void) sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
manager_flip_auto_status(m, false);
m->confirm_spawn = false;
manager_set_first_boot(m, false);
assert(m);
if (*generator)
return log_oom();
free(p);
const char *s = NULL;
return -EINVAL;
return log_oom();
free(p);
return log_oom();
if (!mkdtemp(p)) {
free(p);
return -errno;
*generator = p;
assert(m);
if (!*generator)
char **path;
assert(m);
if (m->test_run)
if (!paths)
return log_oom();
goto found;
goto finish;
goto finish;
goto finish;
assert(m);
if (!*generator)
assert(m);
assert(m);
l = m->environment;
return -ENOMEM;
strv_free(a);
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)
assert(m);
if (m->first_boot != (int) b) {
m->first_boot = b;
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
assert(m);
assert(m);
unsigned size;
assert(m);
if (failed) {
return log_oom();
return log_oom();
Unit *u;
assert(m);
return MANAGER_INITIALIZING;
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;