manager.c revision 8a3a1704c7738a49385e1e1a2a5041f50e79f57e
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2010 Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Lesser General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering/* Where clients shall send notification messages to */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int manager_setup_notify(Manager *m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to allocate notification socket: %m");
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (getpid() != 1 || detect_container(NULL) > 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("Failed to add timer change fd to epoll: %m");
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering m->notify_socket = strdup(sa.un.sun_path);
7dfbe2e3fc0215b49d8202a32beb6b1aae08c4e4Tom Gundersen log_debug("Using notification socket %s", m->notify_socket);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int manager_setup_time_change(Manager *m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(m->time_change_watch.type == WATCH_INVALID);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering m->time_change_watch.type = WATCH_TIME_CHANGE;
b2c23da8cea1987a1a329f5a964d3299b7ca7890Lennart Poettering m->time_change_watch.fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to create timerfd: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* We only care for the cancellation event, hence we set the
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * timeout to the latest possible value. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert_cc(sizeof(time_t) == sizeof(long));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering close_nointr_nofail(m->time_change_watch.fd);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->time_change_watch.fd, &ev) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to add timer change fd to epoll: %m");
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Enable that we get SIGINT on control-alt-del. In containers
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * this will fail with EPERM (older) or EINVAL (newer), so
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * ignore that. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_warning("Failed to enable ctrl-alt-del handling: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Support systems without virtual console */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_warning("Failed to open /dev/tty0: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Enable that we get SIGWINCH on kbrequest */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poetteringstatic int manager_setup_signals(Manager *m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* We are not interested in SIGSTOP and friends. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGINT, /* Kernel sends us this on control-alt-del */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+0, /* systemd: start default.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+1, /* systemd: isolate rescue.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+2, /* systemd: isolate emergency.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+3, /* systemd: start halt.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+4, /* systemd: start poweroff.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+5, /* systemd: start reboot.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+6, /* systemd: start kexec.target */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+13, /* systemd: Immediate halt */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+14, /* systemd: Immediate poweroff */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+15, /* systemd: Immediate reboot */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+16, /* systemd: Immediate kexec */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+20, /* systemd: enable status messages */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+21, /* systemd: disable status messages */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+27, /* systemd: set log target to console */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering SIGRTMIN+28, /* systemd: set log target to kmsg */
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic void manager_strip_environment(Manager *m) {
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poettering /* Remove variables from the inherited set that are part of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * the container interface:
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering strv_remove_prefix(m->environment, "container=");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering strv_remove_prefix(m->environment, "container_");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Remove variables from the inherited set that are part of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * the initrd interface:
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering strv_remove_prefix(m->environment, "RD_");
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringint manager_new(SystemdRunningAs running_as, Manager **_m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering dual_timestamp_get(&m->userspace_timestamp);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek m->exit_code = _MANAGER_EXIT_CODE_INVALID;
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek m->idle_pipe[0] = m->idle_pipe[1] = -1;
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poettering m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering m->default_controllers = strv_new("cpu", NULL);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
be847e82cf95bf8eb589778df2aa2b3d1d7ae99eLennart Poettering m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Try to connect to the busses, if possible. */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = bus_init(m, running_as != SYSTEMD_SYSTEM);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic unsigned manager_dispatch_cleanup_queue(Manager *m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering unsigned n = 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering while ((u = m->cleanup_queue)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering GC_OFFSET_GOOD, /* We still need this unit */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering GC_OFFSET_BAD, /* We don't need this unit anymore */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic void unit_gc_sweep(Unit *u, unsigned gc_marker) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering u->gc_marker == gc_marker + GC_OFFSET_BAD ||
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* We were unable to find anything out about this entry, so
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * let's investigate it later */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering u->gc_marker = gc_marker + GC_OFFSET_UNSURE;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* We definitely know that this one is not useful anymore, so
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * let's mark it for deletion */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering u->gc_marker = gc_marker + GC_OFFSET_BAD;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering u->gc_marker = gc_marker + GC_OFFSET_GOOD;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic unsigned manager_dispatch_gc_queue(Manager *m) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering unsigned n = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering while ((u = m->gc_queue)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering LIST_REMOVE(Unit, gc_queue, m->gc_queue, u);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering u->gc_marker = gc_marker + GC_OFFSET_BAD;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic void manager_clear_jobs_and_units(Manager *m) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering for (c = 0; c < _UNIT_TYPE_MAX; c++)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* If we reexecute ourselves, we keep the root cgroup
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poettering manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering close_nointr_nofail(m->time_change_watch.fd);
05a08cb60f02970e8476306074c70ee4e6a57fb3Thomas Hindoe Paaboel Andersen strv_free(m->default_controllers);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (i = 0; i < RLIMIT_NLIMITS; i++)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Let's ask every type to load all units from disk/kernel
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * that it might know */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (c = 0; c < _UNIT_TYPE_MAX; c++)
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if ((q = unit_vtable[c]->enumerate(m)) < 0)
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Then, let's set up their initial state. */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* ignore aliases */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if ((q = unit_coldplug(u)) < 0)
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poetteringstatic void manager_build_unit_path_cache(Manager *m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) {
82a2b6bb5e4e5d294f09af778c48974a7857afb6Lennart Poettering log_error("Failed to allocate unit path cache.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* This simply builds a list of files we know exist, so that
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * we don't always have to go to disk */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering STRV_FOREACH(i, m->lookup_paths.unit_path) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (!(d = opendir(*i))) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("Failed to open directory: %m");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if ((r = set_put(m->unit_path_cache, p)) < 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to build unit path cache: %s", strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* If we will deserialize make sure that during enumeration
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * this is already known, so we increase the counter here
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* First, enumerate what we can from all config files */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* Second, deserialize if there is something to deserialize */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering q = manager_deserialize(m, serialization, fds);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* Third, fire things up! */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (mode == JOB_ISOLATE && type != JOB_START) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (mode == JOB_ISOLATE && !unit->allow_isolate) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
dcc2fc01fa850e9ee36c549dc2691e7e5c71bebfLennart Poettering r = transaction_activate(tr, m, mode, e);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) tr->anchor_job->id);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringint manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering r = manager_load_unit(m, name, NULL, NULL, &unit);
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering return manager_add_job(m, type, unit, mode, override, e, _ret);
bd5f920f1288c0d4d488629fadf067f709227030Lennart PoetteringJob *manager_get_job(Manager *m, uint32_t id) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering return hashmap_get(m->jobs, UINT32_TO_PTR(id));
bd5f920f1288c0d4d488629fadf067f709227030Lennart PoetteringUnit *manager_get_unit(Manager *m, const char *name) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poetteringunsigned manager_dispatch_load_queue(Manager *m) {
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering unsigned n = 0;
a9c8343e83ec09f80a76930573b2592f97ae4283Daniel Mack /* Make sure we are not run recursively */
bd5f920f1288c0d4d488629fadf067f709227030Lennart Poettering /* Dispatches the load queue. Takes a unit from the queue and
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * tries to load its data until the queue is empty */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering while ((u = m->load_queue)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* This will prepare the unit for loading, but not actually
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering * load anything from disk. */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering ret = unit_new(m, unit_vtable[t]->object_size);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if ((r = unit_add_name(ret, name)) < 0) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringint manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering /* This will load the service information files, but not actually
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering * start any services or anything. */
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering r = manager_load_unit_prepare(m, name, path, e, _ret);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringvoid manager_dump_units(Manager *s, FILE *f, const char *prefix) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const char *t;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* No need to recurse. We're cancelling all jobs. */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering job_finish_and_invalidate(j, JOB_CANCELED, false);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringunsigned manager_dispatch_run_queue(Manager *m) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering unsigned n = 0;
2f671520ebade4877cbf6aca3572a5f8c4e1871dLennart Poettering while ((j = m->run_queue)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringunsigned manager_dispatch_dbus_queue(Manager *m) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering unsigned n = 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering while ((u = m->dbus_unit_queue)) {
0faacd470dfbd24f4c6504da6f04213aa05f9d19Lennart Poettering while ((j = m->dbus_job_queue)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int manager_process_notify_fd(Manager *m) {
700ff4d97311902a440109a2c081731ab6ae8a20Lennart Poettering uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
e05ad7bcc87f652cea321224f8eeb32e21d18e0cLennart Poettering if ((n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT)) <= 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering control.cmsghdr.cmsg_level != SOL_SOCKET ||
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_warning("Received notify message without credentials. Ignoring.");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid))))
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (!(u = cgroup_unit_by_pid(m, ucred->pid))) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Got notification message for unit %s", u->id);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int manager_dispatch_sigchld(Manager *m) {
Unit *u;
return -errno;
if ((r = manager_process_notify_fd(m)) < 0)
return -errno;
ssize_t n;
bool sigchld = false;
assert(m);
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);
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 (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 (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;
Unit *u;
if (feof(f))
r = -errno;
goto finish;
goto finish;
goto finish;
if (ferror(f)) {
r = -EIO;
goto finish;
m->n_reloading --;
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;
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);
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();
free(p);
return log_oom();
if (!mkdtemp(p)) {
free(p);
return -errno;
*generator = p;
assert(m);
if (!*generator)
const char *generator_path;
mode_t u;
assert(m);
goto finish;
goto finish;
goto finish;
umask(u);
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();
assert(w);