manager.c revision e21fea24ae2a7a04f6d5c9d2bbbaf5833d248952
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright 2010 Lennart Poettering
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer systemd is free software; you can redistribute it and/or modify it
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer under the terms of the GNU Lesser General Public License as published by
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer the Free Software Foundation; either version 2.1 of the License, or
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt (at your option) any later version.
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt systemd is distributed in the hope that it will be useful, but
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt WITHOUT ANY WARRANTY; without even the implied warranty of
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1c36b4a73b876258fbe01fbe9bc9b750b7dcc9ceEvgeny Vereshchagin Lesser General Public License for more details.
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier You should have received a copy of the GNU Lesser General Public License
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier/* Initial delay and the interval for printing status messages about running jobs */
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier/* Where clients shall send notification messages to */
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmekstatic int manager_setup_notify(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to allocate notification socket: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (getpid() != 1 || detect_container(NULL) > 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin r = setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin r = epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev);
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin log_error("Failed to add notification socket fd to epoll: %m");
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin m->notify_socket = strdup(sa.un.sun_path);
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin log_debug("Using notification socket %s", m->notify_socket);
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchaginstatic int manager_jobs_in_progress_mod_timer(Manager *m) {
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin .it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC,
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin .it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC,
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin if (timerfd_settime(m->jobs_in_progress_watch.fd, 0, &its, NULL) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_watch_jobs_in_progress(Manager *m) {
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin if (m->jobs_in_progress_watch.type != WATCH_INVALID)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->jobs_in_progress_watch.type = WATCH_JOBS_IN_PROGRESS;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->jobs_in_progress_watch.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek log_error("Failed to create timerfd: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to set up timer for jobs progress watch: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->jobs_in_progress_watch.fd, &ev) < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to add jobs progress timer fd to epoll: %m");
1b1eae69ce52ef6c89a1200e8d3758549b291991Daniel Mack close_nointr_nofail(m->jobs_in_progress_watch.fd);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void manager_unwatch_jobs_in_progress(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->jobs_in_progress_watch.fd, NULL) >= 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier close_nointr_nofail(m->jobs_in_progress_watch.fd);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#define CYLON_BUFFER_EXTRA (2*strlen(ANSI_RED_ON) + strlen(ANSI_HIGHLIGHT_RED_ON) + 2*strlen(ANSI_HIGHLIGHT_OFF))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
5a613464fa15c0960b418322f592a24b9e0f7455Evgeny Vereshchagin assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
5a613464fa15c0960b418322f592a24b9e0f7455Evgeny Vereshchagin assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchaginstatic void manager_print_jobs_in_progress(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (j->state == JOB_RUNNING && counter++ == print_nr)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* m->n_running_jobs must be consistent with the contents of m->jobs,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * so the above loop must have succeeded in finding j. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier cylon_pos = m->jobs_in_progress_iteration % 14;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier manager_status_printf(m, true, cylon, "%sA %s job is running for %s",
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier strempty(job_of_n), job_type_to_string(j->type), unit_description(j->unit));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_watch_idle_pipe(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->idle_pipe_watch.type != WATCH_INVALID)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->idle_pipe_watch.fd, &ev) < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to add idle_pipe fd to epoll: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void manager_unwatch_idle_pipe(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->idle_pipe_watch.fd, NULL) >= 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_setup_time_change(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* We only care for the cancellation event, hence we set the
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * timeout to the latest possible value. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin assert(m->time_change_watch.type == WATCH_INVALID);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->time_change_watch.type = WATCH_TIME_CHANGE;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->time_change_watch.fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier close_nointr_nofail(m->time_change_watch.fd);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->time_change_watch.fd, &ev) < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to add timer change fd to epoll: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int enable_special_signals(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Enable that we get SIGINT on control-alt-del. In containers
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * this will fail with EPERM (older) or EINVAL (newer), so
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * ignore that. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to enable ctrl-alt-del handling: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Support systems without virtual console */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to open /dev/tty0: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Enable that we get SIGWINCH on kbrequest */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We are not interested in SIGSTOP and friends. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGINT, /* Kernel sends us this on control-alt-del */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+0, /* systemd: start default.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+1, /* systemd: isolate rescue.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+2, /* systemd: isolate emergency.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+4, /* systemd: start poweroff.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+20, /* systemd: enable status messages */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+21, /* systemd: disable status messages */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+27, /* systemd: set log target to console */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+28, /* systemd: set log target to kmsg */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int manager_default_environment(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *path = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *path = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin";
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* The system manager always starts with a clean
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * environment for its children. It does not import
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * the kernel or the parents exported variables.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * The initial passed environ is untouched to keep
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * /proc/self/environ valid; it is used for tagging
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * the init process inside containers. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Import locale variables LC_*= from configuration */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* The user manager passes its own environment
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * along to its children. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_new(SystemdRunningAs running_as, bool reexecuting, Manager **_m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer efi_get_boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->cgroup_unit = hashmap_new(string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->watch_bus = hashmap_new(string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Try to connect to the busses, if possible. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS")) ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = bus_init(m, reexecuting || running_as != SYSTEMD_SYSTEM);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_debug("Skipping DBus session bus connection attempt - no DBUS_SESSION_BUS_ADDRESS set...");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic unsigned manager_dispatch_cleanup_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->cleanup_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_BAD, /* We don't need this unit anymore */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void unit_gc_sweep(Unit *u, unsigned gc_marker) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We were unable to find anything out about this entry, so
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * let's investigate it later */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We definitely know that this one is not useful anymore, so
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * let's mark it for deletion */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic unsigned manager_dispatch_gc_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* log_debug("Running GC..."); */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->gc_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void manager_clear_jobs_and_units(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (c = 0; c < _UNIT_TYPE_MAX; c++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* If we reexecute ourselves, we keep the root cgroup
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_nointr_nofail(m->jobs_in_progress_watch.fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (i = 0; i < RLIMIT_NLIMITS; i++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Let's ask every type to load all units from disk/kernel
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * that it might know */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (c = 0; c < _UNIT_TYPE_MAX; c++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Then, let's set up their initial state. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* ignore aliases */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->id != k)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((q = unit_coldplug(u)) < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void manager_build_unit_path_cache(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->unit_path_cache = set_new(string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to allocate unit path cache.");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* This simply builds a list of files we know exist, so that
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * we don't always have to go to disk */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to open directory %s: %m", *i);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to build unit path cache: %s", strerror(-r));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->generators_start_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->generators_finish_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* If we will deserialize make sure that during enumeration
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * this is already known, so we increase the counter here
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * already */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* First, enumerate what we can from all config files */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->unitsload_start_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->unitsload_finish_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Second, deserialize if there is something to deserialize */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer q = manager_deserialize(m, serialization, fds);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Any fds left? Find some unit which wants them. This is
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * useful to allow container managers to pass some file
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * descriptors to us pre-initialized. This enables
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * socket-based activation of entire containers. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Third, fire things up! */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Let's wait for the UnitNew/JobNew messages being
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * sent, before we notify that the reload is
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * finished */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (mode == JOB_ISOLATE && type != JOB_START) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start.");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (mode == JOB_ISOLATE && !unit->allow_isolate) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_to_string(type), job_mode_to_string(mode));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_to_string(type), (unsigned) tr->anchor_job->id);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = manager_load_unit(m, name, NULL, NULL, &unit);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return manager_add_job(m, type, unit, mode, override, e, _ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return hashmap_get(m->jobs, UINT32_TO_PTR(id));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald HoyerUnit *manager_get_unit(Manager *m, const char *name) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerunsigned manager_dispatch_load_queue(Manager *m) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unsigned n = 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Make sure we are not run recursively */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Dispatches the load queue. Takes a unit from the queue and
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * tries to load its data until the queue is empty */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer while ((u = m->load_queue)) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *name,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *path,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* This will prepare the unit for loading, but not actually
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * load anything from disk. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer ret = unit_new(m, unit_vtable[t]->object_size);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *name,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *path,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* This will load the service information files, but not actually
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * start any services or anything. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = manager_load_unit_prepare(m, name, path, e, _ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyervoid manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyervoid manager_dump_units(Manager *s, FILE *f, const char *prefix) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->id == t)
2c393ed7611a586ef5665aa62453ec57c0f5fef6Evgeny Vereshchagin /* No need to recurse. We're cancelling all jobs. */
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer job_finish_and_invalidate(j, JOB_CANCELED, false);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerunsigned manager_dispatch_run_queue(Manager *m) {
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((j = m->run_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerunsigned manager_dispatch_dbus_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->dbus_unit_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((j = m->dbus_job_queue)) {
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;
case WATCH_IDLE_PIPE: {
m->no_console_output = true;
close_idle_pipe(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_run_queue(m) > 0)
if (bus_dispatch(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);
r = unit_name_from_dbus_path(s, &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)
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;
} 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;
goto finish;
m->n_reloading --;
Unit *u;
Iterator i;
assert(m);
FILE *f;
assert(m);
r = manager_open_serialization(m, &f);
m->n_reloading ++;
bus_broadcast_reloading(m, true);
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--;
m->send_reloading_done = true;
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_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)
close_idle_pipe(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();
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);
char **e = NULL;
assert(m);
return -ENOMEM;
m->environment = e;
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->no_console_output)
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);