manager.c revision b215b0ede11c0dda90009c8412609d2416150075
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers This file is part of systemd.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers Copyright 2010 Lennart Poettering
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers systemd is free software; you can redistribute it and/or modify it
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers under the terms of the GNU Lesser General Public License as published by
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers the Free Software Foundation; either version 2.1 of the License, or
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers (at your option) any later version.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers systemd is distributed in the hope that it will be useful, but
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers Lesser General Public License for more details.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers You should have received a copy of the GNU Lesser General Public License
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers/* Initial delay and the interval for printing status messages about running jobs */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
a660c63c551b88136ac6176855b5907cc533e848Kay Sieversstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a660c63c551b88136ac6176855b5907cc533e848Kay Sieversstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a660c63c551b88136ac6176855b5907cc533e848Kay Sieversstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
de892aea1c486b59e04884268b612081d1660514Kay Sieversstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
a660c63c551b88136ac6176855b5907cc533e848Kay Sieversstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
a5c32cff1f56afe6f0c6c70d91a88a7a8238b2d7Harald Hoyerstatic void manager_undo_generators(Manager *m);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic void manager_watch_jobs_in_progress(Manager *m) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers (void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED)-1) + sizeof(ANSI_HIGHLIGHT_RED)-1 + 2*(sizeof(ANSI_NORMAL)-1))
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sieversstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sieversvoid manager_flip_auto_status(Manager *m, bool enable) {
de892aea1c486b59e04884268b612081d1660514Kay Sievers manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
de892aea1c486b59e04884268b612081d1660514Kay Sieversstatic void manager_print_jobs_in_progress(Manager *m) {
f168c27313e4d7b0aabee037dc9c78a5799f0597Thomas Hindoe Paaboel Andersen _cleanup_free_ char *job_of_n = NULL;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek manager_flip_auto_status(m, true);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek if (j->state == JOB_RUNNING && counter++ == print_nr)
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers /* m->n_running_jobs must be consistent with the contents of m->jobs,
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers * so the above loop must have succeeded in finding j. */
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (job_get_timeout(j, &x) > 0)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers "%sA %s job is running for %s (%s / %s)",
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sieversstatic int have_ask_password(void) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return false;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return false;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return true;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sieversstatic int manager_dispatch_ask_password_fd(sd_event_source *source,
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers /* Log error but continue. Negative have_ask_password
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers * is treated as unknown status. */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sieversstatic void manager_close_ask_password(Manager *m) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
bb26309dd042c79de907f103d83f398b9436cde0Rob Clarkstatic int manager_check_ask_password(Manager *m) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers mkdir_p_label("/run/systemd/ask-password", 0755);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return log_error_errno(errno, "inotify_init1() failed: %m");
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers log_error_errno(errno, "Failed to add watch on /run/systemd/ask-password: %m");
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers r = sd_event_add_io(m->event, &m->ask_password_event_source,
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (r < 0) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers log_error_errno(errno, "Failed to add event source for /run/systemd/ask-password: %m");
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers (void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* Queries might have been added meanwhile... */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers manager_dispatch_ask_password_fd(m->ask_password_event_source,
d5a89d7dc17a5ba5cf4fc71f82963c5c94a31c3dKay Sievers r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return log_error_errno(r, "Failed to watch idle pipe: %m");
d5a89d7dc17a5ba5cf4fc71f82963c5c94a31c3dKay Sievers (void) sd_event_source_set_description(m->idle_pipe_event_source, "manager-idle-pipe");
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic void manager_close_idle_pipe(Manager *m) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sieversstatic int manager_setup_time_change(Manager *m) {
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers /* We only care for the cancellation event, hence we set the
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers * timeout to the latest possible value. */
f4ddacbd4de0f159ec598f8ad690466a84787ec5Kay Sievers assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen return log_error_errno(errno, "Failed to create timerfd: %m");
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen log_debug_errno(errno, "Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->time_change_fd = safe_close(m->time_change_fd);
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen return log_error_errno(r, "Failed to create time change event source: %m");
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen (void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Bruecknerstatic int enable_special_signals(Manager *m) {
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Enable that we get SIGINT on control-alt-del. In containers
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * this will fail with EPERM (older) or EINVAL (newer), so
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * ignore that. */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Support systems without virtual console */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner log_warning_errno(errno, "Failed to open /dev/tty0: %m");
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Enable that we get SIGWINCH on kbrequest */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Bruecknerstatic int manager_setup_signals(Manager *m) {
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* We make liberal use of realtime signals here. On
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * Linux/glibc we have 30 of them (with the exception of Linux
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * on hppa, see below), between SIGRTMIN+0 ... SIGRTMIN+30
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * (aka SIGRTMAX). */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGINT, /* Kernel sends us this on control-alt-del */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGRTMIN+1, /* systemd: isolate rescue.target */
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers SIGRTMIN+2, /* systemd: isolate emergency.target */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers SIGRTMIN+4, /* systemd: start poweroff.target */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* ... space for more special targets ... */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* ... space for more immediate system state changes ... */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers SIGRTMIN+20, /* systemd: enable status messages */
971e7fb62548f2c9c4e32684bb13409e6579dc6aKay Sievers SIGRTMIN+21, /* systemd: disable status messages */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* .. one free signal here ... */
a4bbef099209d4e3bccd913cd30da536f8971064Kay Sievers /* Apparently Linux on hppa has fewer RT
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers * signals (SIGRTMAX is SIGRTMIN+25 there),
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * hence let's not try to make use of them
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * here. Since these commands are accessible
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers * by different means and only really a safety
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * net, the missing functionality on hppa
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers * shouldn't matter. */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers SIGRTMIN+27, /* systemd: set log target to console */
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek SIGRTMIN+28, /* systemd: set log target to kmsg */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg (obsolete) */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* ... one free signal here SIGRTMIN+30 ... */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m);
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers (void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* Process signals a bit earlier than the rest of things, but
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers * later than notify_fd processing, so that the notify
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers * processing can still figure out to which process/service a
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers * message belongs, before we reap the process. */
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers r = sd_event_source_set_priority(m->signal_event_source, -5);
090be8653471e1abe3f1cdd32eaad0fbd65f85cdThomas Hindoe Paaboel Andersen if (m->running_as == MANAGER_SYSTEM)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sieversstatic void manager_clean_environment(Manager *m) {
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* Let's remove some environment variables that we
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers * need ourselves to communicate with our clients */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "NOTIFY_SOCKET",
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "MANAGERPID",
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "LISTEN_PID",
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "LISTEN_FDS",
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "LISTEN_FDNAMES",
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "WATCHDOG_PID",
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers "WATCHDOG_USEC",
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Bruecknerstatic int manager_default_environment(Manager *m) {
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers /* The system manager always starts with a clean
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * environment for its children. It does not import
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * the kernel or the parents exported variables.
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * The initial passed environ is untouched to keep
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers * /proc/self/environ valid; it is used for tagging
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers * the init process inside containers. */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* Import locale variables LC_*= from configuration */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* The user manager passes its own environment
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers * along to its children. */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversint manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers static const char * const unit_log_fields[_MANAGER_RUNNING_AS_MAX] = {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers static const char * const unit_log_format_strings[_MANAGER_RUNNING_AS_MAX] = {
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (running_as == MANAGER_SYSTEM && detect_container() <= 0)
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers m->default_timer_accuracy_usec = USEC_PER_MINUTE;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* Prepare log fields we can use for structured logging */
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers m->unit_log_field = unit_log_fields[running_as];
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->unit_log_format_string = unit_log_format_strings[running_as];
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = -1;
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers m->have_ask_password = -EINVAL; /* we don't know */
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen m->cgroup_netclass_registry_last = CGROUP_NETCLASS_FIXED_MAX;
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers /* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers RATELIMIT_INIT(m->ctrl_alt_del_ratelimit, 2 * USEC_PER_SEC, 7);
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:
Unit *u;
Iterator i;
assert(m);
assert(m);
r = manager_run_generators(m);
r = lookup_paths_init(
NULL,
if (serialization)
m->n_reloading ++;
r = manager_enumerate(m);
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, 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,
q = manager_enumerate(m);
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;