manager.c revision 49888ca9ef9cac69bfc9b6e30e4f8e3376dcae03
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering This file is part of systemd.
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering Copyright 2010 Lennart Poettering
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering (at your option) any later version.
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering systemd is distributed in the hope that it will be useful, but
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering Lesser General Public License for more details.
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskog#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskog/* Initial delay and the interval for printing status messages about running jobs */
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskog#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering/* Where clients shall send notification messages to */
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic int manager_watch_jobs_in_progress(Manager *m) {
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering return sd_event_add_monotonic(m->event, next, 0, manager_dispatch_jobs_in_progress, m, &m->jobs_in_progress_event_source);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poetteringstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
if (enable) {
Iterator i;
Job *j;
unsigned cylon_pos;
uint64_t x;
assert(m);
manager_flip_auto_status(m, true);
assert(j);
if (job_get_timeout(j, &x) > 0)
assert(m);
if (m->idle_pipe_event_source)
r = sd_event_add_io(m->event, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m, &m->idle_pipe_event_source);
assert(m);
assert(m);
if (m->time_change_fd < 0) {
return -errno;
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_fd, EPOLLIN, manager_dispatch_time_change_fd, m, &m->time_change_event_source);
assert(m);
if (fd < 0) {
assert(m);
if (m->signal_fd < 0)
return -errno;
r = sd_event_add_io(m->event, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m, &m->signal_event_source);
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
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;
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);
} sa = {
if (m->notify_fd < 0) {
if (fd < 0) {
return -errno;
return -errno;
return -errno;
if (!m->notify_socket)
return log_oom();
if (!m->notify_event_source) {
r = sd_event_add_io(m->event, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m, &m->notify_event_source);
return -errno;
#ifdef ENABLE_KDBUS
#ifdef ENABLE_KDBUS
assert(m);
if (m->kdbus_fd >= 0)
m->kdbus_fd = bus_kernel_create_bus(m->running_as == SYSTEMD_SYSTEM ? "system" : "user", m->running_as == SYSTEMD_SYSTEM, &p);
if (m->kdbus_fd < 0) {
return m->kdbus_fd;
bool try_bus_connect;
assert(m);
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;
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_NLIMITS; 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)
if ((q = unit_coldplug(u)) < 0)
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;
case SIGCHLD:
sigchld = true;
case SIGTERM:
case SIGINT:
case SIGWINCH:
case SIGPWR:
case SIGUSR1: {
Unit *u;
bus_init(m, true);
case SIGUSR2: {
if (ferror(f)) {
case SIGHUP:
static const char * const target_table[] = {
[0] = SPECIAL_DEFAULT_TARGET,
[0] = MANAGER_HALT,
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;
bus_serialize(m, f);
if (u->id != t)
if (!unit_can_serialize(u))
m->n_reloading --;
m->n_reloading --;
if (ferror(f))
return -EIO;
assert(m);
assert(f);
m->n_reloading ++;
if (feof(f))
r = -errno;
goto finish;
uint32_t n;
m->n_installed_jobs += n;
uint32_t n;
m->n_failed_jobs += n;
if (!uce) {
r = -ENOMEM;
goto finish;
r = -ENOMEM;
goto finish;
m->environment = e;
int fd;
if (m->notify_fd >= 0) {
r = -ENOMEM;
goto finish;
m->notify_socket = n;
int fd;
if (m->kdbus_fd >= 0)
} else if (bus_deserialize_item(m, l) == 0)
Unit *u;
if (feof(f))
r = -errno;
goto finish;
goto finish;
goto finish;
if (ferror(f))
r = -EIO;
m->n_reloading --;
assert(m);
r = manager_open_serialization(m, &f);
m->n_reloading ++;
bus_manager_send_reloading(m, true);
if (!fds) {
m->n_reloading --;
return -ENOMEM;
m->n_reloading --;
m->n_reloading --;
return -errno;
q = lookup_paths_init(
q = manager_enumerate(m);
fclose(f);
f = NULL;
q = manager_setup_notify(m);
q = manager_coldplug(m);
m->n_reloading--;
m->send_reloading_done = true;
Unit *u;
assert(m);
return !!u->job;
assert(m);
return m->n_reloading != 0;
Unit *u;
Iterator i;
assert(m);
Unit *u;
assert(m);
return unit_inactive_or_pending(u);
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
assert(m);
if (m->n_running_jobs == 0)
if (m->jobs_in_progress_event_source) {
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_NLIMITS; 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))
if (!manager_is_booting_or_shutting_down(m))
assert(m);
return -ENOMEM;
if (!found) {
assert(m);