manager.c revision a47806fafaec9a52a80e1795ad880b9b5008c4b8
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering This file is part of systemd.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Copyright 2010 Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is free software; you can redistribute it and/or modify it
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering under the terms of the GNU Lesser General Public License as published by
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (at your option) any later version.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is distributed in the hope that it will be useful, but
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Lesser General Public License for more details.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering You should have received a copy of the GNU Lesser General Public License
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/* Initial delay and the interval for printing status messages about running jobs */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_run_generators(Manager *m);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void manager_undo_generators(Manager *m);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void manager_watch_jobs_in_progress(Manager *m) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED)-1) + sizeof(ANSI_HIGHLIGHT_RED)-1 + 2*(sizeof(ANSI_NORMAL)-1))
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringvoid manager_flip_auto_status(Manager *m, bool enable) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (m->show_status == SHOW_STATUS_TEMPORARY)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering manager_set_show_status(m, SHOW_STATUS_AUTO);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void manager_print_jobs_in_progress(Manager *m) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (j->state == JOB_RUNNING && counter++ == print_nr)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* m->n_running_jobs must be consistent with the contents of m->jobs,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * so the above loop must have succeeded in finding j. */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering cylon_pos = m->jobs_in_progress_iteration % 14;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "%sA %s job is running for %s (%s / %s)",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int have_ask_password(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dir = opendir("/run/systemd/ask-password");
if (!de)
assert(m);
if (m->have_ask_password < 0)
assert(m);
assert(m);
if (!m->ask_password_event_source) {
if (m->ask_password_inotify_fd < 0)
if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
return -errno;
return -errno;
return m->have_ask_password;
assert(m);
if (m->idle_pipe_event_source)
r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
assert(m);
assert(m);
if (m->test_run)
if (m->time_change_fd < 0)
if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
assert(m);
if (fd < 0) {
assert(m);
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:
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, 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,
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;