manager.c revision b3680f49e20c51e31c8dea84a11207df7b8f0100
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering This file is part of systemd.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering Copyright 2010 Lennart Poettering
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering systemd is free software; you can redistribute it and/or modify it
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering under the terms of the GNU Lesser General Public License as published by
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering (at your option) any later version.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering systemd is distributed in the hope that it will be useful, but
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering Lesser General Public License for more details.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering You should have received a copy of the GNU Lesser General Public License
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering/* Initial delay and the interval for printing status messages about running jobs */
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering/* Where clients shall send notification messages to */
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poetteringstatic int manager_setup_notify(Manager *m) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering log_error("Failed to allocate notification socket: %m");
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering if (getpid() != 1 || detect_container(NULL) > 0)
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering r = setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering r = epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering log_error("Failed to add notification socket fd to epoll: %m");
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering log_debug("Using notification socket %s", m->notify_socket);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic int manager_jobs_in_progress_mod_timer(Manager *m) {
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering .it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC,
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering .it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC,
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering if (timerfd_settime(m->jobs_in_progress_watch.fd, 0, &its, NULL) < 0)
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic int manager_watch_jobs_in_progress(Manager *m) {
df758e98754016119a9c8d49213a636a80ffab22Kay Sievers if (m->jobs_in_progress_watch.type != WATCH_INVALID)
df758e98754016119a9c8d49213a636a80ffab22Kay Sievers m->jobs_in_progress_watch.type = WATCH_JOBS_IN_PROGRESS;
ccd06097c79218f7d5ea4c21721bbcbc7c467dcaZbigniew Jędrzejewski-Szmek m->jobs_in_progress_watch.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering log_error("Failed to set up timer for jobs progress watch: %s", strerror(-r));
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->jobs_in_progress_watch.fd, &ev) < 0) {
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering log_error("Failed to add jobs progress timer fd to epoll: %m");
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering log_debug("Set up jobs progress timerfd.");
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering close_nointr_nofail(m->jobs_in_progress_watch.fd);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic void manager_unwatch_jobs_in_progress(Manager *m) {
e1d758033dc7e101ab32323a0f1649d8daf56a22Ronny Chevalier if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->jobs_in_progress_watch.fd, NULL) >= 0);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering close_nointr_nofail(m->jobs_in_progress_watch.fd);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering log_debug("Closed jobs progress timerfd.");
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering#define CYLON_BUFFER_EXTRA (2*strlen(ANSI_RED_ON) + strlen(ANSI_HIGHLIGHT_RED_ON) + 2*strlen(ANSI_HIGHLIGHT_OFF))
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poetteringstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
Iterator i;
Job *j;
unsigned cylon_pos;
return -errno;
if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
return -errno;
int fd;
assert(m);
if (fd < 0) {
assert(m);
return -errno;
return -errno;
return enable_special_signals(m);
assert(m);
Manager *m;
int r = -ENOMEM;
return -ENOMEM;
#ifdef ENABLE_EFI
if (!m->environment)
goto fail;
if (!m->default_controllers)
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
if (m->epoll_fd < 0)
goto fail;
r = manager_setup_signals(m);
goto fail;
r = manager_setup_cgroup(m);
goto fail;
r = manager_setup_notify(m);
goto fail;
r = manager_setup_time_change(m);
goto fail;
goto fail;
*_m = m;
fail:
manager_free(m);
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);
(m->gc_queue_timestamp <= 0 ||
while ((u = m->gc_queue)) {
u->in_gc_queue = false;
m->n_in_gc_queue = 0;
m->gc_queue_timestamp = 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->epoll_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;
free(p);
goto fail;
closedir(d);
d = NULL;
fail:
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 --;
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *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, DBusError *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;
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
UnitType t;
assert(m);
return -EINVAL;
if (!name)
return -EINVAL;
if (ret) {
if (!ret)
return -ENOMEM;
if (path) {
return -ENOMEM;
if (_ret)
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;
if (m->dispatching_run_queue)
m->dispatching_run_queue = true;
while ((j = m->run_queue)) {
m->dispatching_run_queue = false;
if (m->n_running_jobs > 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;
ssize_t n;
assert(m);
} control = {};
Unit *u;
return -EIO;
return -errno;
buf[n] = 0;
if (!tags)
return log_oom();
assert(m);
Unit *u;
return -errno;
r = manager_process_notify_fd(m);
return -errno;
ssize_t n;
bool sigchld = false;
assert(m);
if (n != sizeof(sfsi)) {
return -EIO;
return -errno;
char *p = NULL;
free(p);
case SIGCHLD:
sigchld = true;
case SIGTERM:
case SIGINT:
case SIGWINCH:
case SIGPWR:
case SIGUSR1: {
Unit *u;
bus_init(m, true);
case SIGUSR2: {
FILE *f;
if (ferror(f)) {
fclose(f);
fclose(f);
case SIGHUP:
static const char * const target_table[] = {
[0] = SPECIAL_DEFAULT_TARGET,
[0] = MANAGER_HALT,
manager_set_show_status(m, true);
manager_set_show_status(m, false);
if (sigchld)
return manager_dispatch_sigchld(m);
Watch *w;
assert(m);
switch (w->type) {
case WATCH_SIGNAL:
return -EINVAL;
if ((r = manager_process_signal_fd(m)) < 0)
case WATCH_NOTIFY:
return -EINVAL;
if ((r = manager_process_notify_fd(m)) < 0)
case WATCH_FD:
case WATCH_UNIT_TIMER:
case WATCH_JOB_TIMER: {
uint64_t v;
ssize_t k;
case WATCH_MOUNT:
case WATCH_SWAP:
case WATCH_UDEV:
case WATCH_DBUS_WATCH:
case WATCH_DBUS_TIMEOUT:
case WATCH_TIME_CHANGE: {
Unit *u;
Iterator i;
NULL);
NULL);
case WATCH_JOBS_IN_PROGRESS: {
uint64_t v;
assert(m);
r = manager_dispatch_sigchld(m);
if (manager_dispatch_load_queue(m) > 0)
if (manager_dispatch_run_queue(m) > 0)
if (bus_dispatch(m) > 0)
if (manager_dispatch_cleanup_queue(m) > 0)
if (manager_dispatch_gc_queue(m) > 0)
if (manager_dispatch_dbus_queue(m) > 0)
if (swap_dispatch_reload(m) > 0)
if (wait_msec <= 0)
return -errno;
return m->exit_code;
Unit *u;
assert(m);
assert(s);
return -EINVAL;
return -ENOMEM;
free(n);
*_u = u;
Job *j;
unsigned id;
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)
free(p);
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) {
goto finish;
log_oom();
goto finish;
errno = 0;
goto finish;
if (fd >= 0)
Manager *m,
const char *name,
const char* old_owner,
const char *new_owner) {
Unit *u;
assert(m);
Manager *m,
const char *name,
Unit *u;
assert(m);
int fd;
FILE *f;
if (!path)
return -ENOMEM;
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)
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;
Unit *u;
if (feof(f))
r = -errno;
goto finish;
goto finish;
goto finish;
if (ferror(f)) {
r = -EIO;
goto finish;
m->n_reloading --;
Unit *u;
Iterator i;
assert(m);
FILE *f;
assert(m);
r = manager_open_serialization(m, &f);
m->n_reloading ++;
if (!fds) {
m->n_reloading --;
r = -ENOMEM;
goto finish;
m->n_reloading --;
goto finish;
m->n_reloading --;
r = -errno;
goto finish;
q = lookup_paths_init(
q = manager_enumerate(m);
fclose(f);
f = NULL;
q = manager_coldplug(m);
m->n_reloading--;
fclose(f);
if (fds)
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_pending_inactive(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)
m->confirm_spawn = false;
if (!log_on_console())
NULL);
initrd_usec = 0;
if (!log_on_console())
NULL);
if (!log_on_console())
NULL);
bus_broadcast_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);
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;
closedir(d);
assert(m);
if (!*generator)
assert(m);
assert(m);
return -ENOMEM;
m->default_controllers = 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);
m->show_status = b;
assert(m);
if (m->show_status)
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(w);