manager.c revision 90b99192ad5b7674585996e2b801679989f8a8a7
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/***
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt This file is part of systemd.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt Copyright 2010 Lennart Poettering
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is free software; you can redistribute it and/or modify it
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt under the terms of the GNU Lesser General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt the Free Software Foundation; either version 2.1 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is distributed in the hope that it will be useful, but
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Lesser General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt You should have received a copy of the GNU Lesser General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt***/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <assert.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <errno.h>
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include <string.h>
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include <signal.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/wait.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <unistd.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/inotify.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <sys/epoll.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/poll.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <sys/reboot.h>
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include <sys/ioctl.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <linux/kd.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <termios.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <fcntl.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/types.h>
8b43440b7ef4b81c69c31de7ff820dc07a780254Lennart Poettering#include <sys/stat.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <dirent.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/timerfd.h>
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#ifdef HAVE_AUDIT
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <libaudit.h>
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering#endif
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "sd-daemon.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "sd-id128.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "sd-messages.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include "manager.h"
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include "transaction.h"
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include "hashmap.h"
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include "macro.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "strv.h"
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt#include "log.h"
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include "util.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "mkdir.h"
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt#include "ratelimit.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "locale-setup.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "mount-setup.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "unit-name.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "missing.h"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#include "path-lookup.h"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#include "special.h"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#include "exit-status.h"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#include "virt.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "watchdog.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "cgroup-util.h"
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen#include "path-util.h"
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams#include "audit-fd.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "boot-timestamps.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "env-util.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "bus-common-errors.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "bus-error.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "bus-util.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "dbus.h"
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt#include "dbus-unit.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "dbus-job.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "dbus-manager.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "bus-kernel.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "time-util.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt/* Initial delay and the interval for printing status messages about running jobs */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#define NOTIFY_FD_MAX 768
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#define NOTIFY_BUFFER_MAX PIPE_BUF
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_run_generators(Manager *m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic void manager_undo_generators(Manager *m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int manager_watch_jobs_in_progress(Manager *m) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt usec_t next;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (m->jobs_in_progress_event_source)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt return sd_event_add_time(
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt m->event,
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt &m->jobs_in_progress_event_source,
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt CLOCK_MONOTONIC,
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt next, 0,
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt manager_dispatch_jobs_in_progress, m);
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt}
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt char *p = buffer;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (pos > 1) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering if (pos > 2)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt p = mempset(p, ' ', pos-2);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt p = stpcpy(p, ANSI_RED_ON);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt *p++ = '*';
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt }
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (pos > 0 && pos <= width) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt p = stpcpy(p, ANSI_HIGHLIGHT_RED_ON);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt *p++ = '*';
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering if (pos < width) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering p = stpcpy(p, ANSI_RED_ON);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering *p++ = '*';
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (pos < width-1)
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams p = mempset(p, ' ', width-1-pos);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams strcpy(p, ANSI_HIGHLIGHT_OFF);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams }
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams}
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flyktvoid manager_flip_auto_status(Manager *m, bool enable) {
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams assert(m);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams if (enable) {
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams if (m->show_status == SHOW_STATUS_AUTO)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams } else {
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams if (m->show_status == SHOW_STATUS_TEMPORARY)
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams manager_set_show_status(m, SHOW_STATUS_AUTO);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams }
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams}
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williamsstatic void manager_print_jobs_in_progress(Manager *m) {
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams _cleanup_free_ char *job_of_n = NULL;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams Iterator i;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Job *j;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt unsigned counter = 0, print_nr;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt char cylon[6 + CYLON_BUFFER_EXTRA + 1];
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt unsigned cylon_pos;
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller uint64_t x;
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering assert(m);
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller assert(m->n_running_jobs > 0);
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller manager_flip_auto_status(m, true);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering HASHMAP_FOREACH(j, m->jobs, i)
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams if (j->state == JOB_RUNNING && counter++ == print_nr)
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams break;
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams /* m->n_running_jobs must be consistent with the contents of m->jobs,
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt * so the above loop must have succeeded in finding j. */
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt assert(counter == print_nr + 1);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen assert(j);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen cylon_pos = m->jobs_in_progress_iteration % 14;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen if (cylon_pos >= 8)
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen cylon_pos = 14 - cylon_pos;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen m->jobs_in_progress_iteration++;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen if (m->n_running_jobs > 1)
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen if (job_get_timeout(j, &x) > 0)
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen "%sA %s job is running for %s (%s / %s)",
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen strempty(job_of_n),
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen job_type_to_string(j->type),
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen unit_description(j->unit),
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen time, limit);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen}
ebe207d4acf38165adbc45298662982eecdb9e9fTom Gundersen
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersenstatic int have_ask_password(void) {
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams _cleanup_closedir_ DIR *dir;
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams dir = opendir("/run/systemd/ask-password");
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams if (!dir) {
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poettering if (errno == ENOENT)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return false;
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt else
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt return -errno;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt for (;;) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt struct dirent *de;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poettering errno = 0;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt de = readdir(dir);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!de && errno != 0)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return -errno;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!de)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return false;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (startswith(de->d_name, "ask."))
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return true;
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering }
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt}
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int manager_dispatch_ask_password_fd(sd_event_source *source,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt int fd, uint32_t revents, void *userdata) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt Manager *m = userdata;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(m);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt flush_fd(fd);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt m->have_ask_password = have_ask_password();
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (m->have_ask_password < 0)
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt /* Log error but continue. Negative have_ask_password
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt * is treated as unknown status. */
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt return 0;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt}
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic void manager_close_ask_password(Manager *m) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(m);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt m->have_ask_password = -EINVAL;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt}
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int manager_check_ask_password(Manager *m) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt int r;
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt assert(m);
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt if (!m->ask_password_event_source) {
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt assert(m->ask_password_inotify_fd < 0);
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
3098562c9236fe0bd3e7d950b6c53907304d277fTom Gundersen mkdir_p_label("/run/systemd/ask-password", 0755);
3098562c9236fe0bd3e7d950b6c53907304d277fTom Gundersen
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt if (m->ask_password_inotify_fd < 0)
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt return log_error_errno(errno, "inotify_init1() failed: %m");
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt log_error_errno(errno, "Failed to add watch on /run/systemd/ask-password: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt manager_close_ask_password(m);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return -errno;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt r = sd_event_add_io(m->event, &m->ask_password_event_source,
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt m->ask_password_inotify_fd, EPOLLIN,
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller manager_dispatch_ask_password_fd, m);
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt if (r < 0) {
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller log_error_errno(errno, "Failed to add event source for /run/systemd/ask-password: %m");
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller manager_close_ask_password(m);
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller return -errno;
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller }
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller /* Queries might have been added meanwhile... */
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller manager_dispatch_ask_password_fd(m->ask_password_event_source,
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt m->ask_password_inotify_fd, EPOLLIN, m);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt }
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return m->have_ask_password;
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flyktstatic int manager_watch_idle_pipe(Manager *m) {
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt int r;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt assert(m);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (m->idle_pipe_event_source)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return 0;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (m->idle_pipe[2] < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return log_error_errno(r, "Failed to watch idle pipe: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return 0;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic void manager_close_idle_pipe(Manager *m) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt assert(m);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt safe_close_pair(m->idle_pipe);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt safe_close_pair(m->idle_pipe + 2);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flyktstatic int manager_setup_time_change(Manager *m) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* We only care for the cancellation event, hence we set the
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt * timeout to the latest possible value. */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct itimerspec its = {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt .it_value.tv_sec = TIME_T_MAX,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt };
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt assert(m);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt if (m->test_run)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return 0;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (m->time_change_fd < 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return log_error_errno(errno, "Failed to create timerfd: %m");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_debug_errno(errno, "Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt m->time_change_fd = safe_close(m->time_change_fd);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return 0;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (r < 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return log_error_errno(r, "Failed to create time change event source: %m");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt return 0;
926695f1b5f9395eeb416cc2f478a9cf75fdbeb4Thomas Hindoe Paaboel Andersen}
926695f1b5f9395eeb416cc2f478a9cf75fdbeb4Thomas Hindoe Paaboel Andersen
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flyktstatic int enable_special_signals(Manager *m) {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt _cleanup_close_ int fd = -1;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt assert(m);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt /* Enable that we get SIGINT on control-alt-del. In containers
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt * this will fail with EPERM (older) or EINVAL (newer), so
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt * ignore that. */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (fd < 0) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* Support systems without virtual console */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (fd != -ENOENT)
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt log_warning_errno(errno, "Failed to open /dev/tty0: %m");
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt } else {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt /* Enable that we get SIGWINCH on kbrequest */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt }
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return 0;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int manager_setup_signals(Manager *m) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct sigaction sa = {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt .sa_handler = SIG_DFL,
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt .sa_flags = SA_NOCLDSTOP|SA_RESTART,
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt };
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt sigset_t mask;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt int r;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt assert(m);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* We make liberal use of realtime signals here. On
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * Linux/glibc we have 30 of them (with the exception of Linux
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * on hppa, see below), between SIGRTMIN+0 ... SIGRTMIN+30
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * (aka SIGRTMAX). */
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert_se(sigemptyset(&mask) == 0);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt sigset_add_many(&mask,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt SIGCHLD, /* Child died */
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt SIGTERM, /* Reexecute daemon */
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt SIGHUP, /* Reload configuration */
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt SIGUSR2, /* systemd: dump status */
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams SIGINT, /* Kernel sends us this on control-alt-del */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+0, /* systemd: start default.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+1, /* systemd: isolate rescue.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+2, /* systemd: isolate emergency.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+3, /* systemd: start halt.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+4, /* systemd: start poweroff.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+5, /* systemd: start reboot.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+6, /* systemd: start kexec.target */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt /* ... space for more special targets ... */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt SIGRTMIN+13, /* systemd: Immediate halt */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+14, /* systemd: Immediate poweroff */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+15, /* systemd: Immediate reboot */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+16, /* systemd: Immediate kexec */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /* ... space for more immediate system state changes ... */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+20, /* systemd: enable status messages */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+21, /* systemd: disable status messages */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* .. one free signal here ... */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt#if !defined(__hppa64__) && !defined(__hppa__)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* Apparently Linux on hppa has fewer RT
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * signals (SIGRTMAX is SIGRTMIN+25 there),
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * hence let's not try to make use of them
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * here. Since these commands are accessible
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * by different means and only really a safety
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * net, the missing functionality on hppa
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * shouldn't matter. */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt SIGRTMIN+27, /* systemd: set log target to console */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt SIGRTMIN+28, /* systemd: set log target to kmsg */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg (obsolete) */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* ... one free signal here SIGRTMIN+30 ... */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt#endif
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt -1);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (m->signal_fd < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return -errno;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return r;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* Process signals a bit earlier than the rest of things, but
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt * later than notify_fd processing, so that the notify
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt * processing can still figure out to which process/service a
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * message belongs, before we reap the process. */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = sd_event_source_set_priority(m->signal_event_source, -5);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (m->running_as == SYSTEMD_SYSTEM)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt return enable_special_signals(m);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic void manager_clean_environment(Manager *m) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(m);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* Let's remove some environment variables that we
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann * need ourselves to communicate with our clients */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt strv_env_unset_many(
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->environment,
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt "NOTIFY_SOCKET",
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt "MAINPID",
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt "MANAGERPID",
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt "LISTEN_PID",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt "LISTEN_FDS",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt "WATCHDOG_PID",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt "WATCHDOG_USEC",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt NULL);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int manager_default_environment(Manager *m) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (m->running_as == SYSTEMD_SYSTEM) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* The system manager always starts with a clean
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * environment for its children. It does not import
4b4923e65423e60d755841b5b264730e8f3deab3Tom Gundersen * the kernel or the parents exported variables.
5e91345094a9e983e7abb2313334e7808bcd2cc2Tom Gundersen *
513a6fa8679510ea1b55967bdb482dd5f8a39f21Ronny Chevalier * The initial passed environ is untouched to keep
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * /proc/self/environ valid; it is used for tagging
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt * the init process inside containers. */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->environment = strv_new("PATH=" DEFAULT_PATH,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt NULL);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* Import locale variables LC_*= from configuration */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt locale_setup(&m->environment);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt } else {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* The user manager passes its own environment
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * along to its children. */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt m->environment = strv_copy(environ);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!m->environment)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return -ENOMEM;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt manager_clean_environment(m);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt strv_sort(m->environment);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt return 0;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt}
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flyktint manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt Manager *m;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(_m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(running_as >= 0);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt m = new0(Manager, 1);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (!m)
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt return -ENOMEM;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt#ifdef ENABLE_EFI
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt#endif
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->running_as = running_as;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->exit_code = _MANAGER_EXIT_CODE_INVALID;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->default_timer_accuracy_usec = USEC_PER_MINUTE;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->ask_password_inotify_fd = -1;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->have_ask_password = -EINVAL; /* we don't know */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt m->test_run = test_run;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = manager_default_environment(m);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (r < 0)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt goto fail;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = hashmap_ensure_allocated(&m->units, &string_hash_ops);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (r < 0)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt goto fail;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = hashmap_ensure_allocated(&m->jobs, NULL);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = hashmap_ensure_allocated(&m->cgroup_unit, &string_hash_ops);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = set_ensure_allocated(&m->startup_units, NULL);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt r = set_ensure_allocated(&m->failed_units, NULL);
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt if (r < 0)
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_default(&m->event);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt goto fail;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
ed19c567e5fcdcec1a2b6dbac63787e001ad5d55Tom Gundersen
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = manager_setup_signals(m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = manager_setup_cgroup(m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = manager_setup_time_change(m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto fail;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->udev = udev_new();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!m->udev) {
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering r = -ENOMEM;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen goto fail;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen }
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* Note that we set up neither kdbus, nor the notify fd
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * here. We do that after deserialization, since they might
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * have gotten serialized across the reexec. */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->taint_usr = dir_is_empty("/usr") > 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt *_m = m;
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktfail:
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt manager_free(m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int manager_setup_notify(Manager *m) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (m->test_run)
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen return 0;
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen if (m->notify_fd < 0) {
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen _cleanup_close_ int fd = -1;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt union sockaddr_union sa = {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt .sa.sa_family = AF_UNIX,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt };
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt static const int one = 1;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* First free all secondary fields */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt free(m->notify_socket);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->notify_socket = NULL;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->notify_event_source = sd_event_source_unref(m->notify_event_source);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (fd < 0)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return log_error_errno(errno, "Failed to allocate notification socket: %m");
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (m->running_as == SYSTEMD_SYSTEM)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt m->notify_socket = strdup("/run/systemd/notify");
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt else {
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const char *e;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen e = getenv("XDG_RUNTIME_DIR");
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!e) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m");
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return -EINVAL;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->notify_socket = strappend(e, "/systemd/notify");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!m->notify_socket)
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek return log_oom();
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt (void) mkdir_parents_label(m->notify_socket, 0755);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt (void) unlink(m->notify_socket);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek if (r < 0)
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return log_error_errno(errno, "SO_PASSCRED failed: %m");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->notify_fd = fd;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt fd = -1;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("Using notification socket %s", m->notify_socket);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!m->notify_event_source) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return log_error_errno(r, "Failed to allocate notify event source: %m");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* Process signals a bit earlier than SIGCHLD, so that we can
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt * still identify to which service an exit message belongs */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = sd_event_source_set_priority(m->notify_event_source, -7);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return log_error_errno(r, "Failed to set priority of notify event source: %m");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int manager_setup_kdbus(Manager *m) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#ifdef ENABLE_KDBUS
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt _cleanup_free_ char *p = NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (m->test_run || m->kdbus_fd >= 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt bus_kernel_fix_attach_mask();
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->kdbus_fd = bus_kernel_create_bus(
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->running_as == SYSTEMD_SYSTEM ? "system" : "user",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->running_as == SYSTEMD_SYSTEM, &p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (m->kdbus_fd < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("Successfully set up kdbus on %s", p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#endif
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int manager_connect_bus(Manager *m, bool reexecuting) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt bool try_bus_connect;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (m->test_run)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt try_bus_connect =
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt m->kdbus_fd >= 0 ||
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt reexecuting ||
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt /* Try to connect to the busses, if possible. */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return bus_init(m, try_bus_connect);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic unsigned manager_dispatch_cleanup_queue(Manager *m) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Unit *u;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt unsigned n = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt while ((u = m->cleanup_queue)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(u->in_cleanup_queue);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt unit_free(u);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt n++;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return n;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt}
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flyktenum {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt GC_OFFSET_UNSURE, /* No clue */
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt GC_OFFSET_GOOD, /* We still need this unit */
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt GC_OFFSET_BAD, /* We don't need this unit anymore */
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt _GC_OFFSET_MAX
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt};
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flyktstatic void unit_gc_sweep(Unit *u, unsigned gc_marker) {
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt Iterator i;
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt Unit *other;
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt bool is_bad;
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt assert(u);
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt u->gc_marker == gc_marker + GC_OFFSET_BAD ||
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt return;
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt if (u->in_cleanup_queue)
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt goto bad;
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt if (unit_check_gc(u))
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt goto good;
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt is_bad = true;
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt unit_gc_sweep(other, gc_marker);
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt goto good;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt is_bad = false;
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt }
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt if (is_bad)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt goto bad;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* We were unable to find anything out about this entry, so
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt * let's investigate it later */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt u->gc_marker = gc_marker + GC_OFFSET_UNSURE;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt unit_add_to_gc_queue(u);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flyktbad:
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt /* We definitely know that this one is not useful anymore, so
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt * let's mark it for deletion */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt u->gc_marker = gc_marker + GC_OFFSET_BAD;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt unit_add_to_cleanup_queue(u);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poetteringgood:
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt u->gc_marker = gc_marker + GC_OFFSET_GOOD;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt}
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktstatic unsigned manager_dispatch_gc_queue(Manager *m) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt Unit *u;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt unsigned n = 0;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt unsigned gc_marker;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt assert(m);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* log_debug("Running GC..."); */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt m->gc_marker += _GC_OFFSET_MAX;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt m->gc_marker = 1;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt gc_marker = m->gc_marker;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt while ((u = m->gc_queue)) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt assert(u->in_gc_queue);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt unit_gc_sweep(u, gc_marker);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt LIST_REMOVE(gc_queue, m->gc_queue, u);
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller u->in_gc_queue = false;
9d89d1ae71cb298218e35a69d6b70e2c94de5271Patrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt n++;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering log_unit_debug(u->id, "Collecting %s", u->id);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt u->gc_marker = gc_marker + GC_OFFSET_BAD;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt unit_add_to_cleanup_queue(u);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt m->n_in_gc_queue = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return n;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic void manager_clear_jobs_and_units(Manager *m) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Unit *u;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt while ((u = hashmap_first(m->units)))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt unit_free(u);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager_dispatch_cleanup_queue(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(!m->load_queue);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(!m->run_queue);
f89087272b5561c9a3fc9d6a4e2a09f75f688fa7Thomas Haller assert(!m->dbus_unit_queue);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(!m->dbus_job_queue);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(!m->cleanup_queue);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(!m->gc_queue);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt assert(hashmap_isempty(m->jobs));
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt assert(hashmap_isempty(m->units));
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->n_on_console = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt m->n_running_jobs = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering
631bbe71298ec892f77f44f94feb612646fe6853Patrik FlyktManager* manager_free(Manager *m) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt UnitType c;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int i;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!m)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager_clear_jobs_and_units(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt for (c = 0; c < _UNIT_TYPE_MAX; c++)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (unit_vtable[c]->shutdown)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt unit_vtable[c]->shutdown(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* If we reexecute ourselves, we keep the root cgroup
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt * around */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager_undo_generators(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
6ec60d20724d2a32e20d25ef75d2af178c242bc2Ronny Chevalier bus_done(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hashmap_free(m->units);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hashmap_free(m->jobs);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hashmap_free(m->watch_pids1);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hashmap_free(m->watch_pids2);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hashmap_free(m->watch_bus);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt set_free(m->startup_units);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt set_free(m->failed_units);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_source_unref(m->signal_event_source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_source_unref(m->notify_event_source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_source_unref(m->time_change_event_source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_source_unref(m->jobs_in_progress_event_source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_source_unref(m->idle_pipe_event_source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_source_unref(m->run_queue_event_source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt safe_close(m->signal_fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt safe_close(m->notify_fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt safe_close(m->time_change_fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt safe_close(m->kdbus_fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager_close_ask_password(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager_close_idle_pipe(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_unref(m->udev);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_unref(m->event);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt free(m->notify_socket);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt lookup_paths_free(&m->lookup_paths);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt strv_free(m->environment);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt hashmap_free(m->cgroup_unit);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt set_free_free(m->unit_path_cache);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann free(m->switch_root);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt free(m->switch_root_init);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt for (i = 0; i < _RLIMIT_MAX; i++)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt free(m->rlimit[i]);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(hashmap_isempty(m->units_requiring_mounts_for));
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hashmap_free(m->units_requiring_mounts_for);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt free(m);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt return NULL;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt}
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flyktint manager_enumerate(Manager *m) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r = 0;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt UnitType c;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt assert(m);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* Let's ask every type to load all units from disk/kernel
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * that it might know */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt for (c = 0; c < _UNIT_TYPE_MAX; c++) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt int q;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c));
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!unit_vtable[c]->enumerate)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann q = unit_vtable[c]->enumerate(m);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (q < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = q;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt manager_dispatch_load_queue(m);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return r;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt}
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int manager_coldplug(Manager *m) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Iterator i;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Unit *u;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt char *k;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(m);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* Then, let's set up their initial state. */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt HASHMAP_FOREACH_KEY(u, k, m->units, i) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int q;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering /* ignore aliases */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (u->id != k)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt q = unit_coldplug(u);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (q < 0)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = q;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return r;
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt}
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flyktstatic void manager_build_unit_path_cache(Manager *m) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt char **i;
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt _cleanup_closedir_ DIR *d = NULL;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt int r;
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering assert(m);
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt set_free_free(m->unit_path_cache);
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt m->unit_path_cache = set_new(&string_hash_ops);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!m->unit_path_cache) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_error("Failed to allocate unit path cache.");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen /* This simply builds a list of files we know exist, so that
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt * we don't always have to go to disk */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt STRV_FOREACH(i, m->lookup_paths.unit_path) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt struct dirent *de;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt d = opendir(*i);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!d) {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (errno != ENOENT)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error_errno(errno, "Failed to open directory %s: %m", *i);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt while ((de = readdir(d))) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt char *p;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (hidden_file(de->d_name))
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!p) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = -ENOMEM;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt goto fail;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = set_consume(m->unit_path_cache, p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt goto fail;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt closedir(d);
ed19c567e5fcdcec1a2b6dbac63787e001ad5d55Tom Gundersen d = NULL;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return;
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktfail:
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_error_errno(r, "Failed to build unit path cache: %m");
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt set_free_free(m->unit_path_cache);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt m->unit_path_cache = NULL;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt}
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktstatic int manager_distribute_fds(Manager *m, FDSet *fds) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt Unit *u;
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering Iterator i;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen int r;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen assert(m);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt HASHMAP_FOREACH(u, m->units, i) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
ed19c567e5fcdcec1a2b6dbac63787e001ad5d55Tom Gundersen if (fdset_size(fds) <= 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt break;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (UNIT_VTABLE(u)->distribute_fds) {
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen r = UNIT_VTABLE(u)->distribute_fds(u, fds);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return r;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return 0;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt}
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktint manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt int r, q;
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen assert(m);
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen dual_timestamp_get(&m->generators_start_timestamp);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = manager_run_generators(m);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt dual_timestamp_get(&m->generators_finish_timestamp);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt return r;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt r = lookup_paths_init(
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt &m->lookup_paths, m->running_as, true,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt NULL,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->generator_unit_path,
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen m->generator_unit_path_early,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt m->generator_unit_path_late);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt manager_build_unit_path_cache(m);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* If we will deserialize make sure that during enumeration
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * this is already known, so we increase the counter here
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt * already */
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering if (serialization)
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen m->n_reloading ++;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen /* First, enumerate what we can from all config files */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt dual_timestamp_get(&m->units_load_start_timestamp);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = manager_enumerate(m);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt dual_timestamp_get(&m->units_load_finish_timestamp);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen /* Second, deserialize if there is something to deserialize */
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen if (serialization)
10c9ce615d98e125bc520efa94aebaef250a4061David Herrmann r = manager_deserialize(m, serialization, fds);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Any fds left? Find some unit which wants them. This is
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * useful to allow container managers to pass some file
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * descriptors to us pre-initialized. This enables
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen * socket-based activation of entire containers. */
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen if (fdset_size(fds) > 0) {
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen q = manager_distribute_fds(m, fds);
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen if (q < 0 && r == 0)
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen r = q;
f667c150a9116022f348cb6d8f2a553dce2386c3Tom Gundersen }
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* We might have deserialized the notify fd, but if we didn't
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt * then let's create the bus now */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt q = manager_setup_notify(m);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (q < 0 && r == 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = q;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* We might have deserialized the kdbus control fd, but if we
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt * didn't, then let's create the bus now. */
63348d13fae61fefcb29133bfae8371b33cf4b6dTom Gundersen manager_setup_kdbus(m);
d7c9c21f18704580f66a1ce73fb6b506fdf40732Patrik Flykt manager_connect_bus(m, !!serialization);
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt /* Third, fire things up! */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt q = manager_coldplug(m);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (q < 0 && r == 0)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = q;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (serialization) {
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller assert(m->n_reloading > 0);
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller m->n_reloading --;
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller /* Let's wait for the UnitNew/JobNew messages being
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt * sent, before we notify that the reload is
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt * finished */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt m->send_reloading_done = true;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return r;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt}
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flyktint manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt int r;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt Transaction *tr;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(m);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(type < _JOB_TYPE_MAX);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(unit);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(mode < _JOB_MODE_MAX);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (mode == JOB_ISOLATE && type != JOB_START)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (mode == JOB_ISOLATE && !unit->allow_isolate)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_unit_debug(unit->id,
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt "Trying to enqueue job %s/%s/%s", unit->id,
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt job_type_to_string(type), job_mode_to_string(mode));
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt job_type_collapse(&type, unit);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!tr)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return -ENOMEM;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt mode == JOB_IGNORE_DEPENDENCIES, e);
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto tr_abort;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (mode == JOB_ISOLATE) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = transaction_add_isolate_jobs(tr, m);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto tr_abort;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = transaction_activate(tr, m, mode, e);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto tr_abort;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_unit_debug(unit->id,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt "Enqueued job %s/%s as %u", unit->id,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt job_type_to_string(type), (unsigned) tr->anchor_job->id);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (_ret)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt *_ret = tr->anchor_job;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt transaction_free(tr);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return 0;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykttr_abort:
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt transaction_abort(tr);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt transaction_free(tr);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktint manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Unit *unit;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(m);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(type < _JOB_TYPE_MAX);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering assert(name);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering assert(mode < _JOB_MODE_MAX);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering r = manager_load_unit(m, name, NULL, NULL, &unit);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering if (r < 0)
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return manager_add_job(m, type, unit, mode, override, e, _ret);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik FlyktJob *manager_get_job(Manager *m, uint32_t id) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(m);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering return hashmap_get(m->jobs, UINT32_TO_PTR(id));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart PoetteringUnit *manager_get_unit(Manager *m, const char *name) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(m);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering assert(name);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return hashmap_get(m->units, name);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering}
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poetteringunsigned manager_dispatch_load_queue(Manager *m) {
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering Unit *u;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering unsigned n = 0;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering assert(m);
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Make sure we are not run recursively */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (m->dispatching_load_queue)
0ae0e5cd96813bacad43a39920a043d8d20a67dbLennart Poettering return 0;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt m->dispatching_load_queue = true;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Dispatches the load queue. Takes a unit from the queue and
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * tries to load its data until the queue is empty */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt while ((u = m->load_queue)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(u->in_load_queue);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering unit_load(u);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt n++;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt m->dispatching_load_queue = false;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return n;
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek}
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktint manager_load_unit_prepare(
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt Manager *m,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt const char *name,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt const char *path,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt sd_bus_error *e,
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt Unit **_ret) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt Unit *ret;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt UnitType t;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(m);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(name || path);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
/* This will prepare the unit for loading, but not actually
* load anything from disk. */
if (path && !is_path(path))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
if (!name)
name = basename(path);
t = unit_name_to_type(name);
if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
ret = manager_get_unit(m, name);
if (ret) {
*_ret = ret;
return 1;
}
ret = unit_new(m, unit_vtable[t]->object_size);
if (!ret)
return -ENOMEM;
if (path) {
ret->fragment_path = strdup(path);
if (!ret->fragment_path) {
unit_free(ret);
return -ENOMEM;
}
}
r = unit_add_name(ret, name);
if (r < 0) {
unit_free(ret);
return r;
}
unit_add_to_load_queue(ret);
unit_add_to_dbus_queue(ret);
unit_add_to_gc_queue(ret);
if (_ret)
*_ret = ret;
return 0;
}
int manager_load_unit(
Manager *m,
const char *name,
const char *path,
sd_bus_error *e,
Unit **_ret) {
int r;
assert(m);
/* This will load the service information files, but not actually
* start any services or anything. */
r = manager_load_unit_prepare(m, name, path, e, _ret);
if (r != 0)
return r;
manager_dispatch_load_queue(m);
if (_ret)
*_ret = unit_follow_merge(*_ret);
return 0;
}
void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
Iterator i;
Job *j;
assert(s);
assert(f);
HASHMAP_FOREACH(j, s->jobs, i)
job_dump(j, f, prefix);
}
void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
Iterator i;
Unit *u;
const char *t;
assert(s);
assert(f);
HASHMAP_FOREACH_KEY(u, t, s->units, i)
if (u->id == t)
unit_dump(u, f, prefix);
}
void manager_clear_jobs(Manager *m) {
Job *j;
assert(m);
while ((j = hashmap_first(m->jobs)))
/* No need to recurse. We're cancelling all jobs. */
job_finish_and_invalidate(j, JOB_CANCELED, false);
}
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
Manager *m = userdata;
Job *j;
assert(source);
assert(m);
while ((j = m->run_queue)) {
assert(j->installed);
assert(j->in_run_queue);
job_run_and_invalidate(j);
}
if (m->n_running_jobs > 0)
manager_watch_jobs_in_progress(m);
if (m->n_on_console > 0)
manager_watch_idle_pipe(m);
return 1;
}
static unsigned manager_dispatch_dbus_queue(Manager *m) {
Job *j;
Unit *u;
unsigned n = 0;
assert(m);
if (m->dispatching_dbus_queue)
return 0;
m->dispatching_dbus_queue = true;
while ((u = m->dbus_unit_queue)) {
assert(u->in_dbus_queue);
bus_unit_send_change_signal(u);
n++;
}
while ((j = m->dbus_job_queue)) {
assert(j->in_dbus_queue);
bus_job_send_change_signal(j);
n++;
}
m->dispatching_dbus_queue = false;
if (m->send_reloading_done) {
m->send_reloading_done = false;
bus_manager_send_reloading(m, false);
}
if (m->queued_message)
bus_send_queued_message(m);
return n;
}
static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
_cleanup_strv_free_ char **tags = NULL;
assert(m);
assert(u);
assert(buf);
assert(n > 0);
tags = strv_split(buf, "\n\r");
if (!tags) {
log_oom();
return;
}
log_unit_debug(u->id, "Got notification message for unit %s", u->id);
if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, pid, tags, fds);
}
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
ssize_t n;
int r;
assert(m);
assert(m->notify_fd == fd);
if (revents != EPOLLIN) {
log_warning("Got unexpected poll event for notify fd.");
return 0;
}
for (;;) {
_cleanup_fdset_free_ FDSet *fds = NULL;
char buf[NOTIFY_BUFFER_MAX+1];
struct iovec iovec = {
.iov_base = buf,
.iov_len = sizeof(buf)-1,
};
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
} control = {};
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
struct ucred *ucred = NULL;
bool found = false;
Unit *u1, *u2, *u3;
int *fd_array = NULL;
unsigned n_fds = 0;
n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
if (errno == EAGAIN || errno == EINTR)
break;
return -errno;
}
if (n == 0)
return -ECONNRESET;
for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
fd_array = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
} else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
ucred = (struct ucred*) CMSG_DATA(cmsg);
}
}
if (n_fds > 0) {
assert(fd_array);
r = fdset_new_array(&fds, fd_array, n_fds);
if (r < 0) {
close_many(fd_array, n_fds);
return log_oom();
}
}
if (!ucred || ucred->pid <= 0) {
log_warning("Received notify message without valid credentials. Ignoring.");
continue;
}
if ((size_t) n >= sizeof(buf)) {
log_warning("Received notify message exceeded maximum size. Ignoring.");
continue;
}
buf[n] = 0;
/* Notify every unit that might be interested, but try
* to avoid notifying the same one multiple times. */
u1 = manager_get_unit_by_pid(m, ucred->pid);
if (u1) {
manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
found = true;
}
u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid));
if (u2 && u2 != u1) {
manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
found = true;
}
u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid));
if (u3 && u3 != u2 && u3 != u1) {
manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
found = true;
}
if (!found)
log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
if (fdset_size(fds) > 0)
log_warning("Got auxiliary fds with notification message, closing all.");
}
return 0;
}
static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
assert(m);
assert(u);
assert(si);
log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
unit_unwatch_pid(u, si->si_pid);
UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
}
static int manager_dispatch_sigchld(Manager *m) {
assert(m);
for (;;) {
siginfo_t si = {};
/* 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;
Unit *u1, *u2, *u3;
get_process_comm(si.si_pid, &name);
log_debug("Child "PID_FMT" (%s) died (code=%s, status=%i/%s)",
si.si_pid, strna(name),
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)));
/* And now figure out the unit this belongs
* to, it might be multiple... */
u1 = manager_get_unit_by_pid(m, si.si_pid);
if (u1)
invoke_sigchld_event(m, u1, &si);
u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid));
if (u2 && u2 != u1)
invoke_sigchld_event(m, u2, &si);
u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid));
if (u3 && u3 != u2 && u3 != u1)
invoke_sigchld_event(m, u3, &si);
}
/* And now, we actually reap the zombie. */
if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
if (errno == EINTR)
continue;
return -errno;
}
}
return 0;
}
static int manager_start_target(Manager *m, const char *name, JobMode mode) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
log_unit_debug(name, "Activating special unit %s", name);
r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
if (r < 0)
log_unit_error(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
return r;
}
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
ssize_t n;
struct signalfd_siginfo sfsi;
bool sigchld = false;
assert(m);
assert(m->signal_fd == fd);
if (revents != EPOLLIN) {
log_warning("Got unexpected events from signal file descriptor.");
return 0;
}
for (;;) {
n = read(m->signal_fd, &sfsi, sizeof(sfsi));
if (n != sizeof(sfsi)) {
if (n >= 0)
return -EIO;
if (errno == EINTR || errno == EAGAIN)
break;
return -errno;
}
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
(sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER)
? LOG_DEBUG : LOG_INFO,
&sfsi);
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: {
_cleanup_free_ char *dump = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t size;
f = open_memstream(&dump, &size);
if (!f) {
log_warning("Failed to allocate memory stream.");
break;
}
manager_dump_units(m, f, "\t");
manager_dump_jobs(m, f, "\t");
if (ferror(f)) {
log_warning("Failed to write status stream");
break;
}
if (fflush(f)) {
log_warning("Failed to flush status stream");
break;
}
log_dump(LOG_INFO, 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, SHOW_STATUS_YES);
break;
case 21:
log_debug("Disabling showing of status.");
manager_set_show_status(m, SHOW_STATUS_NO);
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:
case 29: /* compatibility: used to be mapped to LOG_TARGET_SYSLOG_OR_KMSG */
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;
default:
log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
}
}
}
}
if (sigchld)
manager_dispatch_sigchld(m);
return 0;
}
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
Iterator i;
Unit *u;
assert(m);
assert(m->time_change_fd == fd);
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
LOG_MESSAGE("Time has been changed"),
NULL);
/* Restart the watch */
m->time_change_event_source = sd_event_source_unref(m->time_change_event_source);
m->time_change_fd = safe_close(m->time_change_fd);
manager_setup_time_change(m);
HASHMAP_FOREACH(u, m->units, i)
if (UNIT_VTABLE(u)->time_change)
UNIT_VTABLE(u)->time_change(u);
return 0;
}
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
assert(m);
assert(m->idle_pipe[2] == fd);
m->no_console_output = m->n_on_console > 0;
m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
manager_close_idle_pipe(m);
return 0;
}
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) {
Manager *m = userdata;
int r;
uint64_t next;
assert(m);
assert(source);
manager_print_jobs_in_progress(m);
next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_PERIOD_USEC;
r = sd_event_source_set_time(source, next);
if (r < 0)
return r;
return sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
}
int manager_loop(Manager *m) {
int r;
RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
assert(m);
m->exit_code = MANAGER_OK;
/* 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. Let's reap them. */
r = manager_dispatch_sigchld(m);
if (r < 0)
return r;
while (m->exit_code == MANAGER_OK) {
usec_t wait_usec;
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_dbus_queue(m) > 0)
continue;
/* Sleep for half the watchdog time */
if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) {
wait_usec = m->runtime_watchdog / 2;
if (wait_usec <= 0)
wait_usec = 1;
} else
wait_usec = USEC_INFINITY;
r = sd_event_run(m->event, wait_usec);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
}
return m->exit_code;
}
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *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) {
const char *p;
unsigned id;
Job *j;
int r;
assert(m);
assert(s);
assert(_j);
p = startswith(s, "/org/freedesktop/systemd1/job/");
if (!p)
return -EINVAL;
r = safe_atou(p, &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
_cleanup_free_ char *p = NULL;
const char *msg;
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_oom();
return;
}
msg = strappenda("unit=", p);
if (audit_log_user_comm_message(audit_fd, type, msg, "systemd", 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_errno(errno, "Failed to send audit message: %m");
}
#endif
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
union sockaddr_union sa = PLYMOUTH_SOCKET;
int n = 0;
_cleanup_free_ char *message = NULL;
_cleanup_close_ int fd = -1;
/* 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 (detect_container(NULL) > 0)
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_errno(errno, "socket() failed: %m");
return;
}
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
log_error_errno(errno, "connect() failed: %m");
return;
}
if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
log_oom();
return;
}
errno = 0;
if (write(fd, message, n + 1) != n + 1)
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
log_error_errno(errno, "Failed to write Plymouth message: %m");
}
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);
u = hashmap_get(m->watch_bus, name);
if (!u)
return;
UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
}
int manager_open_serialization(Manager *m, FILE **_f) {
const char *path;
int fd = -1;
FILE *f;
assert(_f);
path = m->running_as == SYSTEMD_SYSTEM ? "/run/systemd" : "/tmp";
fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
log_debug("Serializing state to %s", path);
f = fdopen(fd, "w+");
if (!f) {
safe_close(fd);
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, "loader-timestamp", &m->loader_timestamp);
dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_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);
dual_timestamp_serialize(f, "security-start-timestamp", &m->security_start_timestamp);
dual_timestamp_serialize(f, "security-finish-timestamp", &m->security_finish_timestamp);
dual_timestamp_serialize(f, "generators-start-timestamp", &m->generators_start_timestamp);
dual_timestamp_serialize(f, "generators-finish-timestamp", &m->generators_finish_timestamp);
dual_timestamp_serialize(f, "units-load-start-timestamp", &m->units_load_start_timestamp);
dual_timestamp_serialize(f, "units-load-finish-timestamp", &m->units_load_finish_timestamp);
}
if (!switching_root) {
STRV_FOREACH(e, m->environment) {
_cleanup_free_ char *ce;
ce = cescape(*e);
if (!ce)
return -ENOMEM;
fprintf(f, "env=%s\n", *e);
}
}
if (m->notify_fd >= 0) {
int copy;
copy = fdset_put_dup(fds, m->notify_fd);
if (copy < 0)
return copy;
fprintf(f, "notify-fd=%i\n", copy);
fprintf(f, "notify-socket=%s\n", m->notify_socket);
}
if (m->kdbus_fd >= 0) {
int copy;
copy = fdset_put_dup(fds, m->kdbus_fd);
if (copy < 0)
return copy;
fprintf(f, "kdbus-fd=%i\n", copy);
}
bus_track_serialize(m->subscribed, f);
fputc('\n', f);
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
if (u->id != t)
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;
b = parse_boolean(l+10);
if (b < 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, "security-start-timestamp="))
dual_timestamp_deserialize(l+25, &m->security_start_timestamp);
else if (startswith(l, "security-finish-timestamp="))
dual_timestamp_deserialize(l+26, &m->security_finish_timestamp);
else if (startswith(l, "generators-start-timestamp="))
dual_timestamp_deserialize(l+27, &m->generators_start_timestamp);
else if (startswith(l, "generators-finish-timestamp="))
dual_timestamp_deserialize(l+28, &m->generators_finish_timestamp);
else if (startswith(l, "units-load-start-timestamp="))
dual_timestamp_deserialize(l+27, &m->units_load_start_timestamp);
else if (startswith(l, "units-load-finish-timestamp="))
dual_timestamp_deserialize(l+28, &m->units_load_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 (startswith(l, "notify-fd=")) {
int fd;
if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_debug("Failed to parse notify fd: %s", l + 10);
else {
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
safe_close(m->notify_fd);
m->notify_fd = fdset_remove(fds, fd);
}
} else if (startswith(l, "notify-socket=")) {
char *n;
n = strdup(l+14);
if (!n) {
r = -ENOMEM;
goto finish;
}
free(m->notify_socket);
m->notify_socket = n;
} else if (startswith(l, "kdbus-fd=")) {
int fd;
if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_debug("Failed to parse kdbus fd: %s", l + 9);
else {
safe_close(m->kdbus_fd);
m->kdbus_fd = fdset_remove(fds, fd);
}
} else {
int k;
k = bus_track_deserialize_item(&m->deserialized_subscribed, l);
if (k < 0)
log_debug_errno(k, "Failed to deserialize bus tracker object: %m");
else if (k == 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;
assert(m->n_reloading > 0);
m->n_reloading --;
return r;
}
int manager_reload(Manager *m) {
int r, q;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_fdset_free_ FDSet *fds = NULL;
assert(m);
r = manager_open_serialization(m, &f);
if (r < 0)
return r;
m->n_reloading ++;
bus_manager_send_reloading(m, true);
fds = fdset_new();
if (!fds) {
m->n_reloading --;
return -ENOMEM;
}
r = manager_serialize(m, f, fds, false);
if (r < 0) {
m->n_reloading --;
return r;
}
if (fseeko(f, 0, SEEK_SET) < 0) {
m->n_reloading --;
return -errno;
}
/* 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 */
q = manager_run_generators(m);
if (q < 0 && r >= 0)
r = q;
q = lookup_paths_init(
&m->lookup_paths, m->running_as, true,
NULL,
m->generator_unit_path,
m->generator_unit_path_early,
m->generator_unit_path_late);
if (q < 0 && r >= 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 >= 0)
r = q;
/* Second, deserialize our stored data */
q = manager_deserialize(m, f, fds);
if (q < 0 && r >= 0)
r = q;
fclose(f);
f = NULL;
/* Re-register notify_fd as event source */
q = manager_setup_notify(m);
if (q < 0 && r >= 0)
r = q;
/* Third, fire things up! */
q = manager_coldplug(m);
if (q < 0 && r >= 0)
r = q;
assert(m->n_reloading > 0);
m->n_reloading--;
m->send_reloading_done = true;
return r;
}
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);
}
static void manager_notify_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;
if (m->test_run)
return;
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;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC="USEC_FMT, kernel_usec,
"INITRD_USEC="USEC_FMT, initrd_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_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;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC="USEC_FMT, kernel_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_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;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"USERSPACE_USEC="USEC_FMT, userspace_usec,
LOG_MESSAGE("Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
NULL);
}
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
sd_notifyf(false,
"READY=1\n"
"STATUS=Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
}
void manager_check_finished(Manager *m) {
Unit *u = NULL;
Iterator i;
assert(m);
if (hashmap_size(m->jobs) > 0) {
if (m->jobs_in_progress_event_source)
sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
return;
}
manager_flip_auto_status(m, false);
/* Notify Type=idle units that we are done now */
m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
manager_close_idle_pipe(m);
/* Turn off confirm spawn now */
m->confirm_spawn = false;
/* No need to update ask password status when we're going non-interactive */
manager_close_ask_password(m);
/* This is no longer the first boot */
manager_set_first_boot(m, false);
if (dual_timestamp_is_set(&m->finish_timestamp))
return;
dual_timestamp_get(&m->finish_timestamp);
manager_notify_finished(m);
SET_FOREACH(u, m->startup_units, i)
if (u->cgroup_path)
cgroup_context_apply(unit_get_cgroup_context(u), unit_get_cgroup_mask(u), u->cgroup_path, manager_state(m));
}
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) {
/* systemd --system, not running --test */
p = strappend("/run/systemd/", name);
if (!p)
return log_oom();
r = mkdir_p_label(p, 0755);
if (r < 0) {
log_error_errno(r, "Failed to create generator directory %s: %m", p);
free(p);
return r;
}
} else if (m->running_as == SYSTEMD_USER) {
const char *s = NULL;
s = getenv("XDG_RUNTIME_DIR");
if (!s)
return -EINVAL;
p = strjoin(s, "/systemd/", name, NULL);
if (!p)
return log_oom();
r = mkdir_p_label(p, 0755);
if (r < 0) {
log_error_errno(r, "Failed to create generator directory %s: %m", p);
free(p);
return r;
}
} else {
/* systemd --system --test */
p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
if (!p)
return log_oom();
if (!mkdtemp(p)) {
log_error_errno(errno, "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;
}
static int manager_run_generators(Manager *m) {
_cleanup_free_ char **paths = NULL;
const char *argv[5];
char **path;
int r;
assert(m);
if (m->test_run)
return 0;
paths = generator_paths(m->running_as);
if (!paths)
return log_oom();
/* Optimize by skipping the whole process by not creating output directories
* if no generators are found. */
STRV_FOREACH(path, paths) {
r = access(*path, F_OK);
if (r == 0)
goto found;
if (errno != ENOENT)
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
}
return 0;
found:
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_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
finish:
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);
return r;
}
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;
}
static 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 **minus, char **plus) {
char **a = NULL, **b = NULL, **l;
assert(m);
l = m->environment;
if (!strv_isempty(minus)) {
a = strv_env_delete(l, 1, minus);
if (!a)
return -ENOMEM;
l = a;
}
if (!strv_isempty(plus)) {
b = strv_env_merge(2, l, plus);
if (!b) {
strv_free(a);
return -ENOMEM;
}
l = b;
}
if (m->environment != l)
strv_free(m->environment);
if (a != l)
strv_free(a);
if (b != l)
strv_free(b);
m->environment = l;
manager_clean_environment(m);
strv_sort(m->environment);
return 0;
}
int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
int i;
assert(m);
for (i = 0; i < _RLIMIT_MAX; 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, ShowStatus mode) {
assert(m);
assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
if (m->running_as != SYSTEMD_SYSTEM)
return;
m->show_status = mode;
if (mode > 0)
touch("/run/systemd/show-status");
else
unlink("/run/systemd/show-status");
}
static bool manager_get_show_status(Manager *m, StatusType type) {
assert(m);
if (m->running_as != SYSTEMD_SYSTEM)
return false;
if (m->no_console_output)
return false;
if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
return false;
/* If we cannot find out the status properly, just proceed. */
if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
return false;
if (m->show_status > 0)
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_set_first_boot(Manager *m, bool b) {
assert(m);
if (m->running_as != SYSTEMD_SYSTEM)
return;
m->first_boot = b;
if (m->first_boot)
touch("/run/systemd/first-boot");
else
unlink("/run/systemd/first-boot");
}
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
va_list ap;
/* If m is NULL, assume we're after shutdown and let the messages through. */
if (m && !manager_get_show_status(m, type))
return;
/* XXX We should totally drop the check for ephemeral here
* and thus effectively make 'Type=idle' pointless. */
if (type == STATUS_TYPE_EPHEMERAL && m && m->n_on_console > 0)
return;
va_start(ap, format);
status_vprintf(status, true, type == STATUS_TYPE_EPHEMERAL, format, ap);
va_end(ap);
}
int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
_cleanup_free_ char *p = NULL;
Unit *found;
assert(m);
assert(path);
assert(suffix);
assert(_found);
p = unit_name_from_path(path, suffix);
if (!p)
return -ENOMEM;
found = manager_get_unit(m, p);
if (!found) {
*_found = NULL;
return 0;
}
*_found = found;
return 1;
}
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
char p[strlen(path)+1];
assert(m);
assert(path);
strcpy(p, path);
path_kill_slashes(p);
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
}
const char *manager_get_runtime_prefix(Manager *m) {
assert(m);
return m->running_as == SYSTEMD_SYSTEM ?
"/run" :
getenv("XDG_RUNTIME_DIR");
}
ManagerState manager_state(Manager *m) {
Unit *u;
assert(m);
/* Did we ever finish booting? If not then we are still starting up */
if (!dual_timestamp_is_set(&m->finish_timestamp)) {
u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
return MANAGER_INITIALIZING;
return MANAGER_STARTING;
}
/* Is the special shutdown target queued? If so, we are in shutdown state */
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))
return MANAGER_STOPPING;
/* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
(u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
return MANAGER_MAINTENANCE;
u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
(u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
return MANAGER_MAINTENANCE;
/* Are there any failed units? If so, we are in degraded mode */
if (set_size(m->failed_units) > 0)
return MANAGER_DEGRADED;
return MANAGER_RUNNING;
}
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
[MANAGER_RUNNING] = "running",
[MANAGER_DEGRADED] = "degraded",
[MANAGER_MAINTENANCE] = "maintenance",
[MANAGER_STOPPING] = "stopping",
};
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);