manager.c revision e21fea24ae2a7a04f6d5c9d2bbbaf5833d248952
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/***
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright 2010 Lennart Poettering
0fe15dc8ddddeb39a5cad1f4f4afa25fa074a5d1Evgeny Vereshchagin
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
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.
c50a4525aa8151b180d5a325e88c5f3812e66c36Martin Pitt
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***/
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <assert.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <errno.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <string.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/epoll.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <signal.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/signalfd.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/wait.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <unistd.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/poll.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/reboot.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/ioctl.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <linux/kd.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <termios.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <fcntl.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/types.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/stat.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <dirent.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <sys/timerfd.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#ifdef HAVE_AUDIT
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include <libaudit.h>
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#endif
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier#include "systemd/sd-daemon.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "systemd/sd-id128.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "systemd/sd-messages.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "manager.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "transaction.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "hashmap.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "macro.h"
b6f0c419e38a960873fe68bf8f89bbb0268eed02Harald Hoyer#include "strv.h"
61fea35e14d84144e6e2122f5cd247f9c7e6245eEvgeny Vereshchagin#include "log.h"
61fea35e14d84144e6e2122f5cd247f9c7e6245eEvgeny Vereshchagin#include "util.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "mkdir.h"
61fea35e14d84144e6e2122f5cd247f9c7e6245eEvgeny Vereshchagin#include "ratelimit.h"
61fea35e14d84144e6e2122f5cd247f9c7e6245eEvgeny Vereshchagin#include "locale-setup.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "mount-setup.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "unit-name.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "dbus-unit.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "dbus-job.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "missing.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "path-lookup.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "special.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "bus-errors.h"
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt#include "exit-status.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "virt.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "watchdog.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "cgroup-util.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "path-util.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "audit-fd.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#include "efivars.h"
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack#include "env-util.h"
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
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#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier/* Initial delay and the interval for printing status messages about running jobs */
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define JOBS_IN_PROGRESS_WAIT_SEC 5
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define JOBS_IN_PROGRESS_PERIOD_SEC 1
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier/* Where clients shall send notification messages to */
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmekstatic int manager_setup_notify(Manager *m) {
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek union {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct sockaddr sa;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct sockaddr_un un;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier } sa = {
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek .sa.sa_family = AF_UNIX,
24be78d72b931b0175f08cee12fd23d631c024bfEvgeny Vereshchagin };
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct epoll_event ev = {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier .events = EPOLLIN,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier .data.ptr = &m->notify_watch,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier };
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier int one = 1, r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->notify_watch.type = WATCH_NOTIFY;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->notify_watch.fd < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to allocate notification socket: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 else
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin sa.un.sun_path[0] = 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = bind(m->notify_watch.fd, &sa.sa,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("bind() failed: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin r = setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin if (r < 0) {
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin log_error("SO_PASSCRED failed: %m");
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin return -errno;
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin }
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin r = epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev);
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin if (r < 0) {
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin log_error("Failed to add notification socket fd to epoll: %m");
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin return -errno;
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin }
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin sa.un.sun_path[0] = '@';
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin m->notify_socket = strdup(sa.un.sun_path);
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin if (!m->notify_socket)
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin return log_oom();
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin log_debug("Using notification socket %s", m->notify_socket);
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchagin
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin return 0;
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin}
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchaginstatic int manager_jobs_in_progress_mod_timer(Manager *m) {
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin struct itimerspec its = {
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin .it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC,
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin .it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC,
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin };
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchagin return 0;
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin if (timerfd_settime(m->jobs_in_progress_watch.fd, 0, &its, NULL) < 0)
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin return -errno;
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin
9974ff63b182e67bf3d3d9262e2bfa84f0a1378bEvgeny Vereshchagin return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_watch_jobs_in_progress(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct epoll_event ev = {
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin .events = EPOLLIN,
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin .data.ptr = &m->jobs_in_progress_watch,
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin };
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin int r;
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin if (m->jobs_in_progress_watch.type != WATCH_INVALID)
ac289ce3f5eb3f13806f7c631c6b23cee18b26daEvgeny Vereshchagin return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->jobs_in_progress_watch.fd < 0) {
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek log_error("Failed to create timerfd: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = -errno;
2375607039517c88df51ef16ddbb624ec1c10654Kay Sievers goto err;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = manager_jobs_in_progress_mod_timer(m);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (r < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to set up timer for jobs progress watch: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier goto err;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier goto err;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Set up jobs progress timerfd.");
1b1eae69ce52ef6c89a1200e8d3758549b291991Daniel Mack
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevaliererr:
edbced8a151c1b7ded685e2ec644950d2adec5f5Harald Hoyer if (m->jobs_in_progress_watch.fd >= 0)
1b1eae69ce52ef6c89a1200e8d3758549b291991Daniel Mack close_nointr_nofail(m->jobs_in_progress_watch.fd);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier watch_init(&m->jobs_in_progress_watch);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek
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 return;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 watch_init(&m->jobs_in_progress_watch);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->jobs_in_progress_iteration = 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Closed jobs progress timerfd.");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 char *p = buffer;
5a613464fa15c0960b418322f592a24b9e0f7455Evgeny Vereshchagin
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 */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (pos > 1) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (pos > 2)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier p = mempset(p, ' ', pos-2);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier p = stpcpy(p, ANSI_RED_ON);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *p++ = '*';
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (pos > 0 && pos <= width) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier p = stpcpy(p, ANSI_HIGHLIGHT_RED_ON);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier *p++ = '*';
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin if (pos < width) {
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin p = stpcpy(p, ANSI_RED_ON);
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin *p++ = '*';
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin if (pos < width-1)
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin p = mempset(p, ' ', width-1-pos);
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin }
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin}
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchaginstatic void manager_print_jobs_in_progress(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier Iterator i;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier Job *j;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier char *job_of_n = NULL;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier unsigned counter = 0, print_nr;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier char cylon[6 + CYLON_BUFFER_EXTRA + 1];
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier unsigned cylon_pos;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier HASHMAP_FOREACH(j, m->jobs, i)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (j->state == JOB_RUNNING && counter++ == print_nr)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier break;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 assert(counter == print_nr + 1);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier cylon_pos = m->jobs_in_progress_iteration % 14;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (cylon_pos >= 8)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier cylon_pos = 14 - cylon_pos;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->n_running_jobs > 1)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier job_of_n = NULL;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 Chevalier free(job_of_n);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->jobs_in_progress_iteration++;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_watch_idle_pipe(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct epoll_event ev = {
bf3a947cb44f31359bba313e0252cbcc0dc95b03Evgeny Vereshchagin .events = EPOLLIN,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier .data.ptr = &m->idle_pipe_watch,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier };
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier int r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->idle_pipe_watch.type != WATCH_INVALID)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->idle_pipe[2] < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->idle_pipe_watch.type = WATCH_IDLE_PIPE;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->idle_pipe_watch.fd = m->idle_pipe[2];
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->idle_pipe_watch.fd < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to create timerfd: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier goto err;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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");
4be4833ece2856e0cacc09f8f8b2c02b320751faMartin Pitt r = -errno;
7d023341c765c205068e33d23d63a4000ec211dfMartin Pitt goto err;
7d023341c765c205068e33d23d63a4000ec211dfMartin Pitt }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Set up idle_pipe watch.");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevaliererr:
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (m->idle_pipe_watch.fd >= 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier close_nointr_nofail(m->idle_pipe_watch.fd);
cffae62bcb6912fbaf1b7b282d9d170c9d308897Martin Pitt watch_init(&m->idle_pipe_watch);
99877b7e3782a51b31bf191825f0335500f52fe5Harald Hoyer return r;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void manager_unwatch_idle_pipe(Manager *m) {
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt if (m->idle_pipe_watch.type != WATCH_IDLE_PIPE)
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt return;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->idle_pipe_watch.fd, NULL) >= 0);
e63b61be5350dbe92ea12e1eeb96dde251ed9292Evgeny Vereshchagin watch_init(&m->idle_pipe_watch);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Closed idle_pipe watch.");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int manager_setup_time_change(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct epoll_event ev = {
0fe15dc8ddddeb39a5cad1f4f4afa25fa074a5d1Evgeny Vereshchagin .events = EPOLLIN,
0fe15dc8ddddeb39a5cad1f4f4afa25fa074a5d1Evgeny Vereshchagin .data.ptr = &m->time_change_watch,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier };
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* We only care for the cancellation event, hence we set the
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier * timeout to the latest possible value. */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier struct itimerspec its = {
0fe15dc8ddddeb39a5cad1f4f4afa25fa074a5d1Evgeny Vereshchagin .it_value.tv_sec = TIME_T_MAX,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier };
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin assert(m->time_change_watch.type == WATCH_INVALID);
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin
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
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 (m->time_change_watch.fd < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("Failed to create timerfd: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 watch_init(&m->time_change_watch);
25b47f96d9601ff566257b2a31bfb5f4bd25d661Marko Myllynen return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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 return -errno;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int enable_special_signals(Manager *m) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier int fd;
53d90f9582f96208b3674da823ad1a3d2c3b1aa4Martin Pitt
5c404f1ab8e96efedb983806443ca982a1b2a372Evgeny Vereshchagin assert(m);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
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
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (fd < 0) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Support systems without virtual console */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (fd != -ENOENT)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to open /dev/tty0: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier } else {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* Enable that we get SIGWINCH on kbrequest */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer close_nointr_nofail(fd);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return 0;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int manager_setup_signals(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sigset_t mask;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct epoll_event ev = {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer .events = EPOLLIN,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer .data.ptr = &m->signal_watch,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer };
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct sigaction sa = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer .sa_handler = SIG_DFL,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer .sa_flags = SA_NOCLDSTOP|SA_RESTART,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer };
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We are not interested in SIGSTOP and friends. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_se(sigemptyset(&mask) == 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sigset_add_many(&mask,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGCHLD, /* Child died */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGTERM, /* Reexecute daemon */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGHUP, /* Reload configuration */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGUSR2, /* systemd: dump status */
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+3, /* systemd: start halt.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+4, /* systemd: start poweroff.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+5, /* systemd: start reboot.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+6, /* systemd: start kexec.target */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+13, /* systemd: Immediate halt */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+14, /* systemd: Immediate poweroff */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+15, /* systemd: Immediate reboot */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SIGRTMIN+16, /* systemd: Immediate kexec */
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 -1);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier m->signal_watch.type = WATCH_SIGNAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->signal_watch.fd < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -errno;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -errno;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->running_as == SYSTEMD_SYSTEM)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return enable_special_signals(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int manager_default_environment(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#ifdef HAVE_SPLIT_USR
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *path = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *path = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin";
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#endif
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->running_as == SYSTEMD_SYSTEM) {
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 *
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 m->environment = strv_new(path, NULL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Import locale variables LC_*= from configuration */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer locale_setup(&m->environment);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* The user manager passes its own environment
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * along to its children. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->environment = strv_copy(environ);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!m->environment)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_new(SystemdRunningAs running_as, bool reexecuting, Manager **_m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Manager *m;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(_m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(running_as >= 0);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m = new0(Manager, 1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!m)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#ifdef ENABLE_EFI
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (detect_container(NULL) <= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer efi_get_boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#endif
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->running_as = running_as;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->exit_code = _MANAGER_EXIT_CODE_INVALID;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->pin_cgroupfs_fd = -1;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer watch_init(&m->signal_watch);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer watch_init(&m->mount_watch);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer watch_init(&m->swap_watch);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer watch_init(&m->udev_watch);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer watch_init(&m->time_change_watch);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer watch_init(&m->jobs_in_progress_watch);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->epoll_fd = m->dev_autofs_fd = -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
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_default_environment(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->cgroup_unit = hashmap_new(string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!m->cgroup_unit)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->watch_bus = hashmap_new(string_hash_func, string_compare_func);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!m->watch_bus)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->epoll_fd < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_setup_signals(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_setup_cgroup(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_setup_notify(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_setup_time_change(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Try to connect to the busses, if possible. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS")) ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer running_as == SYSTEMD_SYSTEM) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = bus_init(m, reexecuting || running_as != SYSTEMD_SYSTEM);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_debug("Skipping DBus session bus connection attempt - no DBUS_SESSION_BUS_ADDRESS set...");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->taint_usr = dir_is_empty("/usr") > 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *_m = m;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerfail:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_free(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic unsigned manager_dispatch_cleanup_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *u;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->cleanup_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(u->in_cleanup_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_free(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n++;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return n;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerenum {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_UNSURE, /* No clue */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_GOOD, /* We still need this unit */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer GC_OFFSET_BAD, /* We don't need this unit anymore */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer _GC_OFFSET_MAX
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer};
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void unit_gc_sweep(Unit *u, unsigned gc_marker) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Iterator i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *other;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer bool is_bad;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker == gc_marker + GC_OFFSET_BAD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->in_cleanup_queue)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto bad;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (unit_check_gc(u))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto good;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer is_bad = true;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_gc_sweep(other, gc_marker);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto good;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer is_bad = false;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (is_bad)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto bad;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We were unable to find anything out about this entry, so
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * let's investigate it later */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker = gc_marker + GC_OFFSET_UNSURE;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_add_to_gc_queue(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerbad:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We definitely know that this one is not useful anymore, so
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * let's mark it for deletion */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker = gc_marker + GC_OFFSET_BAD;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_add_to_cleanup_queue(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyergood:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker = gc_marker + GC_OFFSET_GOOD;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic unsigned manager_dispatch_gc_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *u;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned gc_marker;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* log_debug("Running GC..."); */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->gc_marker += _GC_OFFSET_MAX;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->gc_marker = 1;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer gc_marker = m->gc_marker;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->gc_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(u->in_gc_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_gc_sweep(u, gc_marker);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer LIST_REMOVE(Unit, gc_queue, m->gc_queue, u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->in_gc_queue = false;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n++;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_debug_unit(u->id, "Collecting %s", u->id);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer u->gc_marker = gc_marker + GC_OFFSET_BAD;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_add_to_cleanup_queue(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->n_in_gc_queue = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return n;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void manager_clear_jobs_and_units(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *u;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = hashmap_first(m->units)))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_free(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_dispatch_cleanup_queue(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(!m->load_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(!m->run_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(!m->dbus_unit_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(!m->dbus_job_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(!m->cleanup_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(!m->gc_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(hashmap_isempty(m->jobs));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(hashmap_isempty(m->units));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->n_on_console = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->n_running_jobs = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void close_idle_pipe(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_pipe(m->idle_pipe);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_pipe(m->idle_pipe + 2);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyervoid manager_free(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer UnitType c;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_clear_jobs_and_units(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (c = 0; c < _UNIT_TYPE_MAX; c++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (unit_vtable[c]->shutdown)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_vtable[c]->shutdown(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* If we reexecute ourselves, we keep the root cgroup
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * around */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_undo_generators(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer bus_done(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hashmap_free(m->units);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hashmap_free(m->jobs);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hashmap_free(m->watch_pids);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hashmap_free(m->watch_bus);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->epoll_fd >= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_nointr_nofail(m->epoll_fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->signal_watch.fd >= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_nointr_nofail(m->signal_watch.fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->notify_watch.fd >= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_nointr_nofail(m->notify_watch.fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->time_change_watch.fd >= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_nointr_nofail(m->time_change_watch.fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->jobs_in_progress_watch.fd >= 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_nointr_nofail(m->jobs_in_progress_watch.fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer free(m->notify_socket);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer lookup_paths_free(&m->lookup_paths);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer strv_free(m->environment);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer hashmap_free(m->cgroup_unit);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer set_free_free(m->unit_path_cache);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer close_idle_pipe(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer free(m->switch_root);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer free(m->switch_root_init);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (i = 0; i < RLIMIT_NLIMITS; i++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer free(m->rlimit[i]);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer free(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_enumerate(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer UnitType c;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
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 if (unit_vtable[c]->enumerate)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((q = unit_vtable[c]->enumerate(m)) < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_dispatch_load_queue(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_coldplug(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Iterator i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *u;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer char *k;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Then, let's set up their initial state. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer HASHMAP_FOREACH_KEY(u, k, m->units, i) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* ignore aliases */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->id != k)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer continue;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((q = unit_coldplug(u)) < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void manager_build_unit_path_cache(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer char **i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer _cleanup_free_ DIR *d = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer set_free_free(m->unit_path_cache);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->unit_path_cache = set_new(string_hash_func, string_compare_func);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!m->unit_path_cache) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to allocate unit path cache.");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
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
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer STRV_FOREACH(i, m->lookup_paths.unit_path) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct dirent *de;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer d = opendir(*i);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!d) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (errno != ENOENT)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to open directory %s: %m", *i);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer continue;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((de = readdir(d))) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer char *p;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ignore_file(de->d_name))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer continue;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!p) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = set_consume(m->unit_path_cache, p);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer goto fail;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer closedir(d);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer d = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerfail:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error("Failed to build unit path cache: %s", strerror(-r));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer set_free_free(m->unit_path_cache);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->unit_path_cache = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r, q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->generators_start_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_run_generators(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->generators_finish_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = lookup_paths_init(
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &m->lookup_paths, m->running_as, true,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->generator_unit_path,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->generator_unit_path_early,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->generator_unit_path_late);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_build_unit_path_cache(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
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 if (serialization)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->n_reloading ++;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* First, enumerate what we can from all config files */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->unitsload_start_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = manager_enumerate(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dual_timestamp_get(&m->unitsload_finish_timestamp);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Second, deserialize if there is something to deserialize */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (serialization) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer q = manager_deserialize(m, serialization, fds);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (q < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
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 if (fdset_size(fds) > 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer q = manager_distribute_fds(m, fds);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (q < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Third, fire things up! */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer q = manager_coldplug(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (q < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = q;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (serialization) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m->n_reloading > 0);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer m->n_reloading --;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
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 Hoyer m->send_reloading_done = true;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Transaction *tr;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(type < _JOB_TYPE_MAX);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(unit);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(mode < _JOB_MODE_MAX);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
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 return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
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 return -EPERM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_debug_unit(unit->id,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer "Trying to enqueue job %s/%s/%s", unit->id,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_to_string(type), job_mode_to_string(mode));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_collapse(&type, unit);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!tr)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -ENOMEM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
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 mode == JOB_IGNORE_DEPENDENCIES, e);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto tr_abort;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (mode == JOB_ISOLATE) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = transaction_add_isolate_jobs(tr, m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto tr_abort;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = transaction_activate(tr, m, mode, e);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto tr_abort;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_debug_unit(unit->id,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer "Enqueued job %s/%s as %u", unit->id,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer job_type_to_string(type), (unsigned) tr->anchor_job->id);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (_ret)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *_ret = tr->anchor_job;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer transaction_free(tr);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyertr_abort:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer transaction_abort(tr);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer transaction_free(tr);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Unit *unit;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(type < _JOB_TYPE_MAX);
c53158818d8cdaf46b3f1b5299b9bda118a1043fThomas Hindoe Paaboel Andersen assert(name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(mode < _JOB_MODE_MAX);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = manager_load_unit(m, name, NULL, NULL, &unit);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return manager_add_job(m, type, unit, mode, override, e, _ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald HoyerJob *manager_get_job(Manager *m, uint32_t id) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return hashmap_get(m->jobs, UINT32_TO_PTR(id));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald HoyerUnit *manager_get_unit(Manager *m, const char *name) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return hashmap_get(m->units, name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerunsigned manager_dispatch_load_queue(Manager *m) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Unit *u;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unsigned n = 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* Make sure we are not run recursively */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (m->dispatching_load_queue)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer m->dispatching_load_queue = true;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
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
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer while ((u = m->load_queue)) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(u->in_load_queue);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unit_load(u);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer n++;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer m->dispatching_load_queue = false;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return n;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_load_unit_prepare(
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Manager *m,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *name,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *path,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer DBusError *e,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Unit **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Unit *ret;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer UnitType t;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(name || path);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* This will prepare the unit for loading, but not actually
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * load anything from disk. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (path && !is_path(path)) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!name)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer name = path_get_file_name(path);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer t = unit_name_to_type(name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
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 return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer ret = manager_get_unit(m, name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *_ret = ret;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 1;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer ret = unit_new(m, unit_vtable[t]->object_size);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!ret)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -ENOMEM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (path) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer ret->fragment_path = strdup(path);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!ret->fragment_path) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unit_free(ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -ENOMEM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = unit_add_name(ret, name);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unit_free(ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unit_add_to_load_queue(ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unit_add_to_dbus_queue(ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer unit_add_to_gc_queue(ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (_ret)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *_ret = ret;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerint manager_load_unit(
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Manager *m,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *name,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *path,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer DBusError *e,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Unit **_ret) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* This will load the service information files, but not actually
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer * start any services or anything. */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = manager_load_unit_prepare(m, name, path, e, _ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r != 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer manager_dispatch_load_queue(m);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (_ret)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer *_ret = unit_follow_merge(*_ret);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyervoid manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer Iterator i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Job *j;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer HASHMAP_FOREACH(j, s->jobs, i)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer job_dump(j, f, prefix);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyervoid manager_dump_units(Manager *s, FILE *f, const char *prefix) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Iterator i;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *u;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(f);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer HASHMAP_FOREACH_KEY(u, t, s->units, i)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (u->id == t)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unit_dump(u, f, prefix);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyervoid manager_clear_jobs(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Job *j;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer while ((j = hashmap_first(m->jobs)))
2c393ed7611a586ef5665aa62453ec57c0f5fef6Evgeny Vereshchagin /* No need to recurse. We're cancelling all jobs. */
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer job_finish_and_invalidate(j, JOB_CANCELED, false);
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer}
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerunsigned manager_dispatch_run_queue(Manager *m) {
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer Job *j;
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer unsigned n = 0;
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer if (m->dispatching_run_queue)
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->dispatching_run_queue = true;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((j = m->run_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(j->installed);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(j->in_run_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer job_run_and_invalidate(j);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n++;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->dispatching_run_queue = false;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->n_running_jobs > 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_watch_jobs_in_progress(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->n_on_console > 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer manager_watch_idle_pipe(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return n;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerunsigned manager_dispatch_dbus_queue(Manager *m) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Job *j;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Unit *u;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer unsigned n = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(m);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->dispatching_dbus_queue)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->dispatching_dbus_queue = true;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((u = m->dbus_unit_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(u->in_dbus_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer bus_unit_send_change_signal(u);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n++;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer while ((j = m->dbus_job_queue)) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(j->in_dbus_queue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer bus_job_send_change_signal(j);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer n++;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->dispatching_dbus_queue = false;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (m->send_reloading_done) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer m->send_reloading_done = false;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer bus_broadcast_reloading(m, false);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return n;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
static int manager_process_notify_fd(Manager *m) {
ssize_t n;
assert(m);
for (;;) {
char buf[4096];
struct iovec iovec = {
.iov_base = buf,
.iov_len = sizeof(buf)-1,
};
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
} control = {};
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
struct ucred *ucred;
Unit *u;
_cleanup_strv_free_ char **tags = NULL;
n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT);
if (n <= 0) {
if (n == 0)
return -EIO;
if (errno == EAGAIN || errno == EINTR)
break;
return -errno;
}
if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
control.cmsghdr.cmsg_level != SOL_SOCKET ||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
log_warning("Received notify message without credentials. Ignoring.");
continue;
}
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid));
if (!u) {
u = manager_get_unit_by_pid(m, ucred->pid);
if (!u) {
log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
continue;
}
}
assert((size_t) n < sizeof(buf));
buf[n] = 0;
tags = strv_split(buf, "\n\r");
if (!tags)
return log_oom();
log_debug_unit(u->id, "Got notification message for unit %s", u->id);
if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags);
}
return 0;
}
static int manager_dispatch_sigchld(Manager *m) {
assert(m);
for (;;) {
siginfo_t si = {};
Unit *u;
int r;
/* First we call waitd() for a PID and do not reap the
* zombie. That way we can still access /proc/$PID for
* it while it is a zombie. */
if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
if (errno == ECHILD)
break;
if (errno == EINTR)
continue;
return -errno;
}
if (si.si_pid <= 0)
break;
if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
_cleanup_free_ char *name = NULL;
get_process_comm(si.si_pid, &name);
log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
}
/* Let's flush any message the dying child might still
* have queued for us. This ensures that the process
* still exists in /proc so that we can figure out
* which cgroup and hence unit it belongs to. */
r = manager_process_notify_fd(m);
if (r < 0)
return r;
/* And now figure out the unit this belongs to */
u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid));
if (!u)
u = manager_get_unit_by_pid(m, si.si_pid);
/* And now, we actually reap the zombie. */
if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
if (errno == EINTR)
continue;
return -errno;
}
if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
continue;
log_debug("Child %lu died (code=%s, status=%i/%s)",
(long unsigned) si.si_pid,
sigchld_code_to_string(si.si_code),
si.si_status,
strna(si.si_code == CLD_EXITED
? exit_status_to_string(si.si_status, EXIT_STATUS_FULL)
: signal_to_string(si.si_status)));
if (!u)
continue;
log_debug_unit(u->id,
"Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
}
return 0;
}
static int manager_start_target(Manager *m, const char *name, JobMode mode) {
int r;
DBusError error;
dbus_error_init(&error);
log_debug_unit(name, "Activating special unit %s", name);
r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
if (r < 0)
log_error_unit(name,
"Failed to enqueue %s job: %s", name, bus_error(&error, r));
dbus_error_free(&error);
return r;
}
static int manager_process_signal_fd(Manager *m) {
ssize_t n;
struct signalfd_siginfo sfsi;
bool sigchld = false;
assert(m);
for (;;) {
n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi));
if (n != sizeof(sfsi)) {
if (n >= 0)
return -EIO;
if (errno == EINTR || errno == EAGAIN)
break;
return -errno;
}
if (sfsi.ssi_pid > 0) {
char *p = NULL;
get_process_comm(sfsi.ssi_pid, &p);
log_debug("Received SIG%s from PID %lu (%s).",
signal_to_string(sfsi.ssi_signo),
(unsigned long) sfsi.ssi_pid, strna(p));
free(p);
} else
log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo));
switch (sfsi.ssi_signo) {
case SIGCHLD:
sigchld = true;
break;
case SIGTERM:
if (m->running_as == SYSTEMD_SYSTEM) {
/* This is for compatibility with the
* original sysvinit */
m->exit_code = MANAGER_REEXECUTE;
break;
}
/* Fall through */
case SIGINT:
if (m->running_as == SYSTEMD_SYSTEM) {
manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
break;
}
/* Run the exit target if there is one, if not, just exit. */
if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
m->exit_code = MANAGER_EXIT;
return 0;
}
break;
case SIGWINCH:
if (m->running_as == SYSTEMD_SYSTEM)
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
break;
case SIGPWR:
if (m->running_as == SYSTEMD_SYSTEM)
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
break;
case SIGUSR1: {
Unit *u;
u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
log_info("Trying to reconnect to bus...");
bus_init(m, true);
}
if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
log_info("Loading D-Bus service...");
manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
}
break;
}
case SIGUSR2: {
FILE *f;
char *dump = NULL;
size_t size;
if (!(f = open_memstream(&dump, &size))) {
log_warning("Failed to allocate memory stream.");
break;
}
manager_dump_units(m, f, "\t");
manager_dump_jobs(m, f, "\t");
if (ferror(f)) {
fclose(f);
free(dump);
log_warning("Failed to write status stream");
break;
}
fclose(f);
log_dump(LOG_INFO, dump);
free(dump);
break;
}
case SIGHUP:
m->exit_code = MANAGER_RELOAD;
break;
default: {
/* Starting SIGRTMIN+0 */
static const char * const target_table[] = {
[0] = SPECIAL_DEFAULT_TARGET,
[1] = SPECIAL_RESCUE_TARGET,
[2] = SPECIAL_EMERGENCY_TARGET,
[3] = SPECIAL_HALT_TARGET,
[4] = SPECIAL_POWEROFF_TARGET,
[5] = SPECIAL_REBOOT_TARGET,
[6] = SPECIAL_KEXEC_TARGET
};
/* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
static const ManagerExitCode code_table[] = {
[0] = MANAGER_HALT,
[1] = MANAGER_POWEROFF,
[2] = MANAGER_REBOOT,
[3] = MANAGER_KEXEC
};
if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
(int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
int idx = (int) sfsi.ssi_signo - SIGRTMIN;
manager_start_target(m, target_table[idx],
(idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
break;
}
if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
(int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
break;
}
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
log_debug("Enabling showing of status.");
manager_set_show_status(m, true);
break;
case 21:
log_debug("Disabling showing of status.");
manager_set_show_status(m, false);
break;
case 22:
log_set_max_level(LOG_DEBUG);
log_notice("Setting log level to debug.");
break;
case 23:
log_set_max_level(LOG_INFO);
log_notice("Setting log level to info.");
break;
case 24:
if (m->running_as == SYSTEMD_USER) {
m->exit_code = MANAGER_EXIT;
return 0;
}
/* This is a nop on init */
break;
case 26:
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_notice("Setting log target to journal-or-kmsg.");
break;
case 27:
log_set_target(LOG_TARGET_CONSOLE);
log_notice("Setting log target to console.");
break;
case 28:
log_set_target(LOG_TARGET_KMSG);
log_notice("Setting log target to kmsg.");
break;
case 29:
log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
log_notice("Setting log target to syslog-or-kmsg.");
break;
default:
log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
}
}
}
}
if (sigchld)
return manager_dispatch_sigchld(m);
return 0;
}
static int process_event(Manager *m, struct epoll_event *ev) {
int r;
Watch *w;
assert(m);
assert(ev);
assert_se(w = ev->data.ptr);
if (w->type == WATCH_INVALID)
return 0;
switch (w->type) {
case WATCH_SIGNAL:
/* An incoming signal? */
if (ev->events != EPOLLIN)
return -EINVAL;
if ((r = manager_process_signal_fd(m)) < 0)
return r;
break;
case WATCH_NOTIFY:
/* An incoming daemon notification event? */
if (ev->events != EPOLLIN)
return -EINVAL;
if ((r = manager_process_notify_fd(m)) < 0)
return r;
break;
case WATCH_FD:
/* Some fd event, to be dispatched to the units */
UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w);
break;
case WATCH_UNIT_TIMER:
case WATCH_JOB_TIMER: {
uint64_t v;
ssize_t k;
/* Some timer event, to be dispatched to the units */
k = read(w->fd, &v, sizeof(v));
if (k != sizeof(v)) {
if (k < 0 && (errno == EINTR || errno == EAGAIN))
break;
log_error("Failed to read timer event counter: %s", k < 0 ? strerror(-k) : "Short read");
return k < 0 ? -errno : -EIO;
}
if (w->type == WATCH_UNIT_TIMER)
UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
else
job_timer_event(w->data.job, v, w);
break;
}
case WATCH_MOUNT:
/* Some mount table change, intended for the mount subsystem */
mount_fd_event(m, ev->events);
break;
case WATCH_SWAP:
/* Some swap table change, intended for the swap subsystem */
swap_fd_event(m, ev->events);
break;
case WATCH_UDEV:
/* Some notification from udev, intended for the device subsystem */
device_fd_event(m, ev->events);
break;
case WATCH_DBUS_WATCH:
bus_watch_event(m, w, ev->events);
break;
case WATCH_DBUS_TIMEOUT:
bus_timeout_event(m, w, ev->events);
break;
case WATCH_TIME_CHANGE: {
Unit *u;
Iterator i;
log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
"MESSAGE=Time has been changed",
NULL);
/* Restart the watch */
epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->time_change_watch.fd,
NULL);
close_nointr_nofail(m->time_change_watch.fd);
watch_init(&m->time_change_watch);
manager_setup_time_change(m);
HASHMAP_FOREACH(u, m->units, i) {
if (UNIT_VTABLE(u)->time_change)
UNIT_VTABLE(u)->time_change(u);
}
break;
}
case WATCH_JOBS_IN_PROGRESS: {
uint64_t v;
/* not interested in the data */
read(w->fd, &v, sizeof(v));
manager_print_jobs_in_progress(m);
break;
}
case WATCH_IDLE_PIPE: {
m->no_console_output = true;
manager_unwatch_idle_pipe(m);
close_idle_pipe(m);
break;
}
default:
log_error("event type=%i", w->type);
assert_not_reached("Unknown epoll event type.");
}
return 0;
}
int manager_loop(Manager *m) {
int r;
RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
assert(m);
m->exit_code = MANAGER_RUNNING;
/* Release the path cache */
set_free_free(m->unit_path_cache);
m->unit_path_cache = NULL;
manager_check_finished(m);
/* There might still be some zombies hanging around from
* before we were exec()'ed. Leat's reap them */
r = manager_dispatch_sigchld(m);
if (r < 0)
return r;
while (m->exit_code == MANAGER_RUNNING) {
struct epoll_event event;
int n;
int wait_msec = -1;
if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
watchdog_ping();
if (!ratelimit_test(&rl)) {
/* Yay, something is going seriously wrong, pause a little */
log_warning("Looping too fast. Throttling execution a little.");
sleep(1);
continue;
}
if (manager_dispatch_load_queue(m) > 0)
continue;
if (manager_dispatch_gc_queue(m) > 0)
continue;
if (manager_dispatch_cleanup_queue(m) > 0)
continue;
if (manager_dispatch_cgroup_queue(m) > 0)
continue;
if (manager_dispatch_run_queue(m) > 0)
continue;
if (bus_dispatch(m) > 0)
continue;
if (manager_dispatch_dbus_queue(m) > 0)
continue;
if (swap_dispatch_reload(m) > 0)
continue;
/* Sleep for half the watchdog time */
if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) {
wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
if (wait_msec <= 0)
wait_msec = 1;
} else
wait_msec = -1;
n = epoll_wait(m->epoll_fd, &event, 1, wait_msec);
if (n < 0) {
if (errno == EINTR)
continue;
return -errno;
} else if (n == 0)
continue;
assert(n == 1);
r = process_event(m, &event);
if (r < 0)
return r;
}
return m->exit_code;
}
int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u) {
_cleanup_free_ char *n = NULL;
Unit *u;
int r;
assert(m);
assert(s);
assert(_u);
r = unit_name_from_dbus_path(s, &n);
if (r < 0)
return r;
r = manager_load_unit(m, n, NULL, e, &u);
if (r < 0)
return r;
*_u = u;
return 0;
}
int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
Job *j;
unsigned id;
int r;
assert(m);
assert(s);
assert(_j);
if (!startswith(s, "/org/freedesktop/systemd1/job/"))
return -EINVAL;
r = safe_atou(s + 30, &id);
if (r < 0)
return r;
j = manager_get_job(m, id);
if (!j)
return -ENOENT;
*_j = j;
return 0;
}
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
#ifdef HAVE_AUDIT
char *p;
int audit_fd;
audit_fd = get_audit_fd();
if (audit_fd < 0)
return;
/* Don't generate audit events if the service was already
* started and we're just deserializing */
if (m->n_reloading > 0)
return;
if (m->running_as != SYSTEMD_SYSTEM)
return;
if (u->type != UNIT_SERVICE)
return;
p = unit_name_to_prefix_and_instance(u->id);
if (!p) {
log_error_unit(u->id,
"Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
return;
}
if (audit_log_user_comm_message(audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
if (errno == EPERM) {
/* We aren't allowed to send audit messages?
* Then let's not retry again. */
close_audit_fd();
} else
log_warning("Failed to send audit message: %m");
}
free(p);
#endif
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
int fd = -1;
union sockaddr_union sa;
int n = 0;
char *message = NULL;
/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
if (m->n_reloading > 0)
return;
if (m->running_as != SYSTEMD_SYSTEM)
return;
if (u->type != UNIT_SERVICE &&
u->type != UNIT_MOUNT &&
u->type != UNIT_SWAP)
return;
/* We set SOCK_NONBLOCK here so that we rather drop the
* message then wait for plymouth */
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
log_error("socket() failed: %m");
return;
}
zero(sa);
sa.sa.sa_family = AF_UNIX;
strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
if (errno != EPIPE &&
errno != EAGAIN &&
errno != ENOENT &&
errno != ECONNREFUSED &&
errno != ECONNRESET &&
errno != ECONNABORTED)
log_error("connect() failed: %m");
goto finish;
}
if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
log_oom();
goto finish;
}
errno = 0;
if (write(fd, message, n + 1) != n + 1) {
if (errno != EPIPE &&
errno != EAGAIN &&
errno != ENOENT &&
errno != ECONNREFUSED &&
errno != ECONNRESET &&
errno != ECONNABORTED)
log_error("Failed to write Plymouth message: %m");
goto finish;
}
finish:
if (fd >= 0)
close_nointr_nofail(fd);
free(message);
}
void manager_dispatch_bus_name_owner_changed(
Manager *m,
const char *name,
const char* old_owner,
const char *new_owner) {
Unit *u;
assert(m);
assert(name);
if (!(u = hashmap_get(m->watch_bus, name)))
return;
UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
}
void manager_dispatch_bus_query_pid_done(
Manager *m,
const char *name,
pid_t pid) {
Unit *u;
assert(m);
assert(name);
assert(pid >= 1);
if (!(u = hashmap_get(m->watch_bus, name)))
return;
UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
}
int manager_open_serialization(Manager *m, FILE **_f) {
char *path = NULL;
int fd;
FILE *f;
assert(_f);
if (m->running_as == SYSTEMD_SYSTEM)
asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
else
asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
if (!path)
return -ENOMEM;
RUN_WITH_UMASK(0077) {
fd = mkostemp(path, O_RDWR|O_CLOEXEC);
}
if (fd < 0) {
free(path);
return -errno;
}
unlink(path);
log_debug("Serializing state to %s", path);
free(path);
f = fdopen(fd, "w+");
if (!f)
return -errno;
*_f = f;
return 0;
}
int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
Iterator i;
Unit *u;
const char *t;
char **e;
int r;
assert(m);
assert(f);
assert(fds);
m->n_reloading ++;
fprintf(f, "current-job-id=%i\n", m->current_job_id);
fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs);
fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs);
dual_timestamp_serialize(f, "firmware-timestamp", &m->firmware_timestamp);
dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_timestamp);
dual_timestamp_serialize(f, "loader-timestamp", &m->loader_timestamp);
dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
if (!in_initrd()) {
dual_timestamp_serialize(f, "userspace-timestamp", &m->userspace_timestamp);
dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
}
if (!switching_root) {
STRV_FOREACH(e, m->environment) {
_cleanup_free_ char *ce;
ce = cescape(*e);
if (ce)
fprintf(f, "env=%s\n", *e);
}
}
bus_serialize(m, f);
fputc('\n', f);
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
if (u->id != t)
continue;
if (!unit_can_serialize(u))
continue;
/* Start marker */
fputs(u->id, f);
fputc('\n', f);
r = unit_serialize(u, f, fds, !switching_root);
if (r < 0) {
m->n_reloading --;
return r;
}
}
assert(m->n_reloading > 0);
m->n_reloading --;
if (ferror(f))
return -EIO;
r = bus_fdset_add_all(m, fds);
if (r < 0)
return r;
return 0;
}
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
int r = 0;
assert(m);
assert(f);
log_debug("Deserializing state...");
m->n_reloading ++;
for (;;) {
char line[LINE_MAX], *l;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
r = 0;
else
r = -errno;
goto finish;
}
char_array_0(line);
l = strstrip(line);
if (l[0] == 0)
break;
if (startswith(l, "current-job-id=")) {
uint32_t id;
if (safe_atou32(l+15, &id) < 0)
log_debug("Failed to parse current job id value %s", l+15);
else
m->current_job_id = MAX(m->current_job_id, id);
} else if (startswith(l, "n-installed-jobs=")) {
uint32_t n;
if (safe_atou32(l+17, &n) < 0)
log_debug("Failed to parse installed jobs counter %s", l+17);
else
m->n_installed_jobs += n;
} else if (startswith(l, "n-failed-jobs=")) {
uint32_t n;
if (safe_atou32(l+14, &n) < 0)
log_debug("Failed to parse failed jobs counter %s", l+14);
else
m->n_failed_jobs += n;
} else if (startswith(l, "taint-usr=")) {
int b;
if ((b = parse_boolean(l+10)) < 0)
log_debug("Failed to parse taint /usr flag %s", l+10);
else
m->taint_usr = m->taint_usr || b;
} else if (startswith(l, "firmware-timestamp="))
dual_timestamp_deserialize(l+19, &m->firmware_timestamp);
else if (startswith(l, "loader-timestamp="))
dual_timestamp_deserialize(l+17, &m->loader_timestamp);
else if (startswith(l, "kernel-timestamp="))
dual_timestamp_deserialize(l+17, &m->kernel_timestamp);
else if (startswith(l, "initrd-timestamp="))
dual_timestamp_deserialize(l+17, &m->initrd_timestamp);
else if (startswith(l, "userspace-timestamp="))
dual_timestamp_deserialize(l+20, &m->userspace_timestamp);
else if (startswith(l, "finish-timestamp="))
dual_timestamp_deserialize(l+17, &m->finish_timestamp);
else if (startswith(l, "env=")) {
_cleanup_free_ char *uce = NULL;
char **e;
uce = cunescape(l+4);
if (!uce) {
r = -ENOMEM;
goto finish;
}
e = strv_env_set(m->environment, uce);
if (!e) {
r = -ENOMEM;
goto finish;
}
strv_free(m->environment);
m->environment = e;
} else if (bus_deserialize_item(m, l) == 0)
log_debug("Unknown serialization item '%s'", l);
}
for (;;) {
Unit *u;
char name[UNIT_NAME_MAX+2];
/* Start marker */
if (!fgets(name, sizeof(name), f)) {
if (feof(f))
r = 0;
else
r = -errno;
goto finish;
}
char_array_0(name);
r = manager_load_unit(m, strstrip(name), NULL, NULL, &u);
if (r < 0)
goto finish;
r = unit_deserialize(u, f, fds);
if (r < 0)
goto finish;
}
finish:
if (ferror(f)) {
r = -EIO;
goto finish;
}
assert(m->n_reloading > 0);
m->n_reloading --;
return r;
}
int manager_distribute_fds(Manager *m, FDSet *fds) {
Unit *u;
Iterator i;
int r;
assert(m);
HASHMAP_FOREACH(u, m->units, i) {
if (fdset_size(fds) <= 0)
break;
if (UNIT_VTABLE(u)->distribute_fds) {
r = UNIT_VTABLE(u)->distribute_fds(u, fds);
if (r < 0)
return r;
}
}
return 0;
}
int manager_reload(Manager *m) {
int r, q;
FILE *f;
FDSet *fds;
assert(m);
r = manager_open_serialization(m, &f);
if (r < 0)
return r;
m->n_reloading ++;
bus_broadcast_reloading(m, true);
fds = fdset_new();
if (!fds) {
m->n_reloading --;
r = -ENOMEM;
goto finish;
}
r = manager_serialize(m, f, fds, false);
if (r < 0) {
m->n_reloading --;
goto finish;
}
if (fseeko(f, 0, SEEK_SET) < 0) {
m->n_reloading --;
r = -errno;
goto finish;
}
/* From here on there is no way back. */
manager_clear_jobs_and_units(m);
manager_undo_generators(m);
lookup_paths_free(&m->lookup_paths);
/* Find new unit paths */
manager_run_generators(m);
q = lookup_paths_init(
&m->lookup_paths, m->running_as, true,
m->generator_unit_path,
m->generator_unit_path_early,
m->generator_unit_path_late);
if (q < 0)
r = q;
manager_build_unit_path_cache(m);
/* First, enumerate what we can from all config files */
q = manager_enumerate(m);
if (q < 0)
r = q;
/* Second, deserialize our stored data */
q = manager_deserialize(m, f, fds);
if (q < 0)
r = q;
fclose(f);
f = NULL;
/* Third, fire things up! */
q = manager_coldplug(m);
if (q < 0)
r = q;
assert(m->n_reloading > 0);
m->n_reloading--;
m->send_reloading_done = true;
finish:
if (f)
fclose(f);
if (fds)
fdset_free(fds);
return r;
}
static bool manager_is_booting_or_shutting_down(Manager *m) {
Unit *u;
assert(m);
/* Is the initial job still around? */
if (manager_get_job(m, m->default_unit_job_id))
return true;
/* Is there a job for the shutdown target? */
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
if (u)
return !!u->job;
return false;
}
bool manager_is_reloading_or_reexecuting(Manager *m) {
assert(m);
return m->n_reloading != 0;
}
void manager_reset_failed(Manager *m) {
Unit *u;
Iterator i;
assert(m);
HASHMAP_FOREACH(u, m->units, i)
unit_reset_failed(u);
}
bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
Unit *u;
assert(m);
assert(name);
/* Returns true if the unit is inactive or going down */
u = manager_get_unit(m, name);
if (!u)
return true;
return unit_inactive_or_pending(u);
}
void manager_check_finished(Manager *m) {
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
assert(m);
if (m->n_running_jobs == 0)
manager_unwatch_jobs_in_progress(m);
if (hashmap_size(m->jobs) > 0) {
manager_jobs_in_progress_mod_timer(m);
return;
}
/* Notify Type=idle units that we are done now */
manager_unwatch_idle_pipe(m);
close_idle_pipe(m);
/* Turn off confirm spawn now */
m->confirm_spawn = false;
if (dual_timestamp_is_set(&m->finish_timestamp))
return;
dual_timestamp_get(&m->finish_timestamp);
if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
* and m->firmware_usec.monotonic and
* m->loader_usec.monotonic should be considered
* negative values. */
firmware_usec = m->firmware_timestamp.monotonic - m->loader_timestamp.monotonic;
loader_usec = m->loader_timestamp.monotonic - m->kernel_timestamp.monotonic;
userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
total_usec = m->firmware_timestamp.monotonic + m->finish_timestamp.monotonic;
if (dual_timestamp_is_set(&m->initrd_timestamp)) {
kernel_usec = m->initrd_timestamp.monotonic - m->kernel_timestamp.monotonic;
initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
if (!log_on_console())
log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
"INITRD_USEC=%llu", (unsigned long long) initrd_usec,
"USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
"MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC),
format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC),
NULL);
} else {
kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic;
initrd_usec = 0;
if (!log_on_console())
log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
"USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
"MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.",
format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC),
NULL);
}
} else {
firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
if (!log_on_console())
log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
"MESSAGE=Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC),
NULL);
}
bus_broadcast_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
sd_notifyf(false,
"READY=1\nSTATUS=Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
}
static int create_generator_dir(Manager *m, char **generator, const char *name) {
char *p;
int r;
assert(m);
assert(generator);
assert(name);
if (*generator)
return 0;
if (m->running_as == SYSTEMD_SYSTEM && getpid() == 1) {
p = strappend("/run/systemd/", name);
if (!p)
return log_oom();
r = mkdir_p_label(p, 0755);
if (r < 0) {
log_error("Failed to create generator directory %s: %s",
p, strerror(-r));
free(p);
return r;
}
} else {
p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
if (!p)
return log_oom();
if (!mkdtemp(p)) {
log_error("Failed to create generator directory %s: %m",
p);
free(p);
return -errno;
}
}
*generator = p;
return 0;
}
static void trim_generator_dir(Manager *m, char **generator) {
assert(m);
assert(generator);
if (!*generator)
return;
if (rmdir(*generator) >= 0) {
free(*generator);
*generator = NULL;
}
return;
}
void manager_run_generators(Manager *m) {
DIR *d = NULL;
const char *generator_path;
const char *argv[5];
int r;
assert(m);
generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
d = opendir(generator_path);
if (!d) {
if (errno == ENOENT)
return;
log_error("Failed to enumerate generator directory %s: %m",
generator_path);
return;
}
r = create_generator_dir(m, &m->generator_unit_path, "generator");
if (r < 0)
goto finish;
r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
if (r < 0)
goto finish;
r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
if (r < 0)
goto finish;
argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
argv[1] = m->generator_unit_path;
argv[2] = m->generator_unit_path_early;
argv[3] = m->generator_unit_path_late;
argv[4] = NULL;
RUN_WITH_UMASK(0022) {
execute_directory(generator_path, d, (char**) argv);
}
trim_generator_dir(m, &m->generator_unit_path);
trim_generator_dir(m, &m->generator_unit_path_early);
trim_generator_dir(m, &m->generator_unit_path_late);
finish:
if (d)
closedir(d);
}
static void remove_generator_dir(Manager *m, char **generator) {
assert(m);
assert(generator);
if (!*generator)
return;
strv_remove(m->lookup_paths.unit_path, *generator);
rm_rf(*generator, false, true, false);
free(*generator);
*generator = NULL;
}
void manager_undo_generators(Manager *m) {
assert(m);
remove_generator_dir(m, &m->generator_unit_path);
remove_generator_dir(m, &m->generator_unit_path_early);
remove_generator_dir(m, &m->generator_unit_path_late);
}
int manager_environment_add(Manager *m, char **environment) {
char **e = NULL;
assert(m);
e = strv_env_merge(2, m->environment, environment);
if (!e)
return -ENOMEM;
strv_free(m->environment);
m->environment = e;
return 0;
}
int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
int i;
assert(m);
for (i = 0; i < RLIMIT_NLIMITS; i++) {
if (!default_rlimit[i])
continue;
m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
if (!m->rlimit[i])
return -ENOMEM;
}
return 0;
}
void manager_recheck_journal(Manager *m) {
Unit *u;
assert(m);
if (m->running_as != SYSTEMD_SYSTEM)
return;
u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
if (u && SOCKET(u)->state != SOCKET_RUNNING) {
log_close_journal();
return;
}
u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE);
if (u && SERVICE(u)->state != SERVICE_RUNNING) {
log_close_journal();
return;
}
/* Hmm, OK, so the socket is fully up and the service is up
* too, then let's make use of the thing. */
log_open();
}
void manager_set_show_status(Manager *m, bool b) {
assert(m);
if (m->running_as != SYSTEMD_SYSTEM)
return;
m->show_status = b;
if (b)
touch("/run/systemd/show-status");
else
unlink("/run/systemd/show-status");
}
static bool manager_get_show_status(Manager *m) {
assert(m);
if (m->running_as != SYSTEMD_SYSTEM)
return false;
if (m->no_console_output)
return false;
if (m->show_status)
return true;
/* If Plymouth is running make sure we show the status, so
* that there's something nice to see when people press Esc */
return plymouth_running();
}
void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) {
va_list ap;
if (!manager_get_show_status(m))
return;
/* XXX We should totally drop the check for ephemeral here
* and thus effectively make 'Type=idle' pointless. */
if (ephemeral && m->n_on_console > 0)
return;
if (!manager_is_booting_or_shutting_down(m))
return;
va_start(ap, format);
status_vprintf(status, true, ephemeral, format, ap);
va_end(ap);
}
void watch_init(Watch *w) {
assert(w);
w->type = WATCH_INVALID;
w->fd = -1;
}