2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2010-02-03 13:03:47 +01:00
|
|
|
|
2009-11-18 00:42:52 +01:00
|
|
|
#include <errno.h>
|
2015-09-22 23:24:07 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <linux/kd.h>
|
2014-10-26 02:30:51 +02:00
|
|
|
#include <sys/epoll.h>
|
2015-09-22 23:24:07 +02:00
|
|
|
#include <sys/inotify.h>
|
2010-02-14 22:39:40 +01:00
|
|
|
#include <sys/ioctl.h>
|
2015-09-22 23:24:07 +02:00
|
|
|
#include <sys/reboot.h>
|
2012-11-25 00:32:40 +01:00
|
|
|
#include <sys/timerfd.h>
|
2015-09-22 23:24:07 +02:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
2010-08-11 15:19:50 +02:00
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_AUDIT
|
2010-08-11 01:43:23 +02:00
|
|
|
#include <libaudit.h>
|
2010-08-11 15:19:50 +02:00
|
|
|
#endif
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
#include "sd-daemon.h"
|
|
|
|
#include "sd-messages.h"
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
#include "sd-path.h"
|
2012-01-05 16:01:58 +01:00
|
|
|
|
2018-05-15 20:17:34 +02:00
|
|
|
#include "all-units.h"
|
2018-10-17 20:40:09 +02:00
|
|
|
#include "alloc-util.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "audit-fd.h"
|
|
|
|
#include "boot-timestamps.h"
|
|
|
|
#include "bus-common-errors.h"
|
|
|
|
#include "bus-error.h"
|
|
|
|
#include "bus-kernel.h"
|
|
|
|
#include "bus-util.h"
|
2016-08-01 19:24:40 +02:00
|
|
|
#include "clean-ipc.h"
|
2017-12-07 11:27:07 +01:00
|
|
|
#include "clock-util.h"
|
2019-08-07 14:58:59 +02:00
|
|
|
#include "core-varlink.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "dbus-job.h"
|
|
|
|
#include "dbus-manager.h"
|
|
|
|
#include "dbus-unit.h"
|
|
|
|
#include "dbus.h"
|
2019-10-24 11:18:35 +02:00
|
|
|
#include "def.h"
|
2016-02-26 18:28:45 +01:00
|
|
|
#include "dirent-util.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "env-util.h"
|
2015-10-23 18:52:53 +02:00
|
|
|
#include "escape.h"
|
2017-01-22 18:35:08 +01:00
|
|
|
#include "exec-util.h"
|
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
|
|
|
#include "execute.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "exit-status.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 18:05:03 +01:00
|
|
|
#include "fileio.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "fs-util.h"
|
2020-03-24 12:17:43 +01:00
|
|
|
#include "generator-setup.h"
|
2009-11-18 00:42:52 +01:00
|
|
|
#include "hashmap.h"
|
2019-07-04 15:46:16 +02:00
|
|
|
#include "install.h"
|
2019-08-07 14:58:59 +02:00
|
|
|
#include "io-util.h"
|
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
|
|
|
#include "label.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "locale-setup.h"
|
2020-05-08 00:26:53 +02:00
|
|
|
#include "load-fragment.h"
|
2010-01-20 19:19:53 +01:00
|
|
|
#include "log.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "macro.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "manager.h"
|
2019-03-13 12:02:21 +01:00
|
|
|
#include "memory-util.h"
|
2012-04-10 21:54:31 +02:00
|
|
|
#include "mkdir.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "path-lookup.h"
|
|
|
|
#include "path-util.h"
|
|
|
|
#include "process-util.h"
|
2010-02-01 03:33:24 +01:00
|
|
|
#include "ratelimit.h"
|
2018-05-03 19:05:59 +02:00
|
|
|
#include "rlimit-util.h"
|
2015-04-04 11:52:57 +02:00
|
|
|
#include "rm-rf.h"
|
2020-09-01 15:49:20 +02:00
|
|
|
#include "selinux-util.h"
|
2018-10-17 20:40:09 +02:00
|
|
|
#include "serialize.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "signal-util.h"
|
2018-05-15 20:17:34 +02:00
|
|
|
#include "socket-util.h"
|
2010-06-18 04:22:59 +02:00
|
|
|
#include "special.h"
|
2015-10-26 22:01:44 +01:00
|
|
|
#include "stat-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "strv.h"
|
2017-12-25 05:08:23 +01:00
|
|
|
#include "strxcpyx.h"
|
2019-09-18 21:02:07 +02:00
|
|
|
#include "sysctl-util.h"
|
2018-05-30 17:57:23 +02:00
|
|
|
#include "syslog-util.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "terminal-util.h"
|
|
|
|
#include "time-util.h"
|
|
|
|
#include "transaction.h"
|
2015-10-26 23:20:41 +01:00
|
|
|
#include "umask-util.h"
|
2015-09-22 23:24:07 +02:00
|
|
|
#include "unit-name.h"
|
2016-08-01 19:24:40 +02:00
|
|
|
#include "user-util.h"
|
2011-09-23 17:20:45 +02:00
|
|
|
#include "virt.h"
|
2012-04-05 22:08:10 +02:00
|
|
|
#include "watchdog.h"
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2015-10-30 11:27:29 +01:00
|
|
|
#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
|
2016-05-04 20:43:23 +02:00
|
|
|
#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
|
2015-10-30 11:27:29 +01:00
|
|
|
|
2013-02-28 00:03:22 +01:00
|
|
|
/* Initial delay and the interval for printing status messages about running jobs */
|
2020-02-29 16:29:42 +01:00
|
|
|
#define JOBS_IN_PROGRESS_WAIT_USEC (2*USEC_PER_SEC)
|
|
|
|
#define JOBS_IN_PROGRESS_QUIET_WAIT_USEC (25*USEC_PER_SEC)
|
2014-01-27 07:15:27 +01:00
|
|
|
#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
|
2013-02-28 00:03:22 +01:00
|
|
|
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
|
|
|
|
|
2019-04-27 02:22:40 +02:00
|
|
|
/* If there are more than 1K bus messages queue across our API and direct buses, then let's not add more on top until
|
2018-02-13 18:30:34 +01:00
|
|
|
* the queue gets more empty. */
|
|
|
|
#define MANAGER_BUS_BUSY_THRESHOLD 1024LU
|
|
|
|
|
|
|
|
/* How many units and jobs to process of the bus queue before returning to the event loop. */
|
|
|
|
#define MANAGER_BUS_MESSAGE_BUDGET 100U
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
2016-05-04 20:43:23 +02:00
|
|
|
static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
|
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
|
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
2016-08-01 19:24:40 +02:00
|
|
|
static int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
|
2013-11-25 15:22:41 +01:00
|
|
|
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
|
2018-01-23 18:18:13 +01:00
|
|
|
static int manager_dispatch_sigchld(sd_event_source *source, void *userdata);
|
2018-05-28 21:33:10 +02:00
|
|
|
static int manager_dispatch_timezone_change(sd_event_source *source, const struct inotify_event *event, void *userdata);
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
static int manager_run_environment_generators(Manager *m);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
static int manager_run_generators(Manager *m);
|
2020-04-27 08:54:44 +02:00
|
|
|
static void manager_vacuum(Manager *m);
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2020-02-29 16:29:42 +01:00
|
|
|
static usec_t manager_watch_jobs_next_time(Manager *m) {
|
|
|
|
return usec_add(now(CLOCK_MONOTONIC),
|
|
|
|
show_status_on(m->show_status) ? JOBS_IN_PROGRESS_WAIT_USEC :
|
|
|
|
JOBS_IN_PROGRESS_QUIET_WAIT_USEC);
|
|
|
|
}
|
|
|
|
|
2015-03-14 03:11:09 +01:00
|
|
|
static void manager_watch_jobs_in_progress(Manager *m) {
|
2014-01-29 00:26:06 +01:00
|
|
|
usec_t next;
|
2015-04-29 20:29:18 +02:00
|
|
|
int r;
|
2014-01-29 00:26:06 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m);
|
2013-02-28 00:03:22 +01:00
|
|
|
|
2016-11-02 10:50:20 +01:00
|
|
|
/* We do not want to show the cylon animation if the user
|
|
|
|
* needs to confirm service executions otherwise confirmation
|
|
|
|
* messages will be screwed by the cylon animation. */
|
2016-11-15 09:29:04 +01:00
|
|
|
if (!manager_is_confirm_spawn_disabled(m))
|
2016-11-02 10:50:20 +01:00
|
|
|
return;
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
if (m->jobs_in_progress_event_source)
|
2015-03-14 03:11:09 +01:00
|
|
|
return;
|
2013-02-28 00:03:22 +01:00
|
|
|
|
2020-02-29 16:29:42 +01:00
|
|
|
next = manager_watch_jobs_next_time(m);
|
2015-04-29 20:29:18 +02:00
|
|
|
r = sd_event_add_time(
|
2014-03-24 02:49:09 +01:00
|
|
|
m->event,
|
|
|
|
&m->jobs_in_progress_event_source,
|
|
|
|
CLOCK_MONOTONIC,
|
|
|
|
next, 0,
|
|
|
|
manager_dispatch_jobs_in_progress, m);
|
2015-04-29 20:29:18 +02:00
|
|
|
if (r < 0)
|
|
|
|
return;
|
2015-04-29 16:05:32 +02:00
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
|
2013-02-28 00:03:22 +01:00
|
|
|
}
|
|
|
|
|
2017-12-14 19:02:29 +01:00
|
|
|
#define CYLON_BUFFER_EXTRA (2*STRLEN(ANSI_RED) + STRLEN(ANSI_HIGHLIGHT_RED) + 2*STRLEN(ANSI_NORMAL))
|
2013-02-28 00:03:22 +01:00
|
|
|
|
|
|
|
static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
|
|
|
|
char *p = buffer;
|
|
|
|
|
|
|
|
assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
|
|
|
|
assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
|
|
|
|
|
|
|
|
if (pos > 1) {
|
2013-03-05 15:52:44 +01:00
|
|
|
if (pos > 2)
|
|
|
|
p = mempset(p, ' ', pos-2);
|
2016-06-10 18:33:15 +02:00
|
|
|
if (log_get_show_color())
|
|
|
|
p = stpcpy(p, ANSI_RED);
|
2013-02-28 00:03:22 +01:00
|
|
|
*p++ = '*';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos > 0 && pos <= width) {
|
2016-06-10 18:33:15 +02:00
|
|
|
if (log_get_show_color())
|
|
|
|
p = stpcpy(p, ANSI_HIGHLIGHT_RED);
|
2013-02-28 00:03:22 +01:00
|
|
|
*p++ = '*';
|
|
|
|
}
|
|
|
|
|
2016-06-10 18:33:15 +02:00
|
|
|
if (log_get_show_color())
|
|
|
|
p = stpcpy(p, ANSI_NORMAL);
|
2013-02-28 00:03:22 +01:00
|
|
|
|
|
|
|
if (pos < width) {
|
2016-06-10 18:33:15 +02:00
|
|
|
if (log_get_show_color())
|
|
|
|
p = stpcpy(p, ANSI_RED);
|
2013-02-28 00:03:22 +01:00
|
|
|
*p++ = '*';
|
2013-03-05 15:52:44 +01:00
|
|
|
if (pos < width-1)
|
|
|
|
p = mempset(p, ' ', width-1-pos);
|
2016-06-10 18:33:15 +02:00
|
|
|
if (log_get_show_color())
|
|
|
|
strcpy(p, ANSI_NORMAL);
|
2013-02-28 00:03:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-27 08:49:53 +02:00
|
|
|
static void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
|
2014-03-12 20:55:13 +01:00
|
|
|
assert(m);
|
|
|
|
|
2014-01-28 04:48:18 +01:00
|
|
|
if (enable) {
|
|
|
|
if (m->show_status == SHOW_STATUS_AUTO)
|
2020-02-29 10:59:27 +01:00
|
|
|
manager_set_show_status(m, SHOW_STATUS_TEMPORARY, reason);
|
2014-01-28 04:48:18 +01:00
|
|
|
} else {
|
|
|
|
if (m->show_status == SHOW_STATUS_TEMPORARY)
|
2020-02-29 10:59:27 +01:00
|
|
|
manager_set_show_status(m, SHOW_STATUS_AUTO, reason);
|
2014-01-28 04:48:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 00:03:22 +01:00
|
|
|
static void manager_print_jobs_in_progress(Manager *m) {
|
2013-11-19 21:12:59 +01:00
|
|
|
_cleanup_free_ char *job_of_n = NULL;
|
2013-02-28 00:03:22 +01:00
|
|
|
Job *j;
|
|
|
|
unsigned counter = 0, print_nr;
|
|
|
|
char cylon[6 + CYLON_BUFFER_EXTRA + 1];
|
|
|
|
unsigned cylon_pos;
|
2014-01-29 00:25:39 +01:00
|
|
|
char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
|
|
|
|
uint64_t x;
|
2013-02-28 00:03:22 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m);
|
2015-01-05 17:22:10 +01:00
|
|
|
assert(m->n_running_jobs > 0);
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2020-02-29 10:59:27 +01:00
|
|
|
manager_flip_auto_status(m, true, "delay");
|
2014-01-28 04:27:07 +01:00
|
|
|
|
2013-02-28 00:03:22 +01:00
|
|
|
print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(j, m->jobs)
|
2013-02-28 00:03:22 +01:00
|
|
|
if (j->state == JOB_RUNNING && counter++ == print_nr)
|
|
|
|
break;
|
|
|
|
|
2013-03-02 12:44:41 +01:00
|
|
|
/* m->n_running_jobs must be consistent with the contents of m->jobs,
|
|
|
|
* so the above loop must have succeeded in finding j. */
|
|
|
|
assert(counter == print_nr + 1);
|
2013-10-12 01:33:48 +02:00
|
|
|
assert(j);
|
2013-03-01 14:57:16 +01:00
|
|
|
|
2013-02-28 00:03:22 +01:00
|
|
|
cylon_pos = m->jobs_in_progress_iteration % 14;
|
|
|
|
if (cylon_pos >= 8)
|
|
|
|
cylon_pos = 14 - cylon_pos;
|
|
|
|
draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
|
|
|
|
|
2014-01-29 00:25:39 +01:00
|
|
|
m->jobs_in_progress_iteration++;
|
|
|
|
|
2015-03-14 03:21:52 +01:00
|
|
|
if (m->n_running_jobs > 1) {
|
|
|
|
if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
|
|
|
|
job_of_n = NULL;
|
|
|
|
}
|
2013-02-28 00:03:22 +01:00
|
|
|
|
2014-01-29 00:25:39 +01:00
|
|
|
format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
|
|
|
|
if (job_get_timeout(j, &x) > 0)
|
|
|
|
format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
|
|
|
|
|
2014-10-28 04:02:54 +01:00
|
|
|
manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
|
2014-01-29 00:25:39 +01:00
|
|
|
"%sA %s job is running for %s (%s / %s)",
|
|
|
|
strempty(job_of_n),
|
|
|
|
job_type_to_string(j->type),
|
2019-06-06 17:33:59 +02:00
|
|
|
unit_status_string(j->unit),
|
2014-01-29 00:25:39 +01:00
|
|
|
time, limit);
|
2013-02-28 00:03:22 +01:00
|
|
|
}
|
|
|
|
|
2014-10-26 02:30:51 +02:00
|
|
|
static int have_ask_password(void) {
|
|
|
|
_cleanup_closedir_ DIR *dir;
|
2016-12-09 10:04:30 +01:00
|
|
|
struct dirent *de;
|
2014-10-26 02:30:51 +02:00
|
|
|
|
|
|
|
dir = opendir("/run/systemd/ask-password");
|
|
|
|
if (!dir) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
2016-12-09 10:04:30 +01:00
|
|
|
FOREACH_DIRENT_ALL(de, dir, return -errno) {
|
2014-10-26 02:30:51 +02:00
|
|
|
if (startswith(de->d_name, "ask."))
|
|
|
|
return true;
|
|
|
|
}
|
2016-12-09 10:04:30 +01:00
|
|
|
return false;
|
2014-10-26 02:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_dispatch_ask_password_fd(sd_event_source *source,
|
|
|
|
int fd, uint32_t revents, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2017-12-12 23:21:09 +01:00
|
|
|
(void) flush_fd(fd);
|
2014-10-26 02:30:51 +02:00
|
|
|
|
|
|
|
m->have_ask_password = have_ask_password();
|
|
|
|
if (m->have_ask_password < 0)
|
|
|
|
/* Log error but continue. Negative have_ask_password
|
|
|
|
* is treated as unknown status. */
|
2014-11-28 17:09:20 +01:00
|
|
|
log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
|
2014-10-26 02:30:51 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_close_ask_password(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
|
2015-08-30 22:13:55 +02:00
|
|
|
m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
|
2014-10-26 02:30:51 +02:00
|
|
|
m->have_ask_password = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_check_ask_password(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!m->ask_password_event_source) {
|
|
|
|
assert(m->ask_password_inotify_fd < 0);
|
|
|
|
|
2019-04-12 09:03:52 +02:00
|
|
|
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
2014-10-26 02:30:51 +02:00
|
|
|
|
|
|
|
m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
|
2014-11-28 19:57:32 +01:00
|
|
|
if (m->ask_password_inotify_fd < 0)
|
2019-03-27 09:30:35 +01:00
|
|
|
return log_error_errno(errno, "Failed to create inotify object: %m");
|
2014-10-26 02:30:51 +02:00
|
|
|
|
2019-09-17 11:16:52 +02:00
|
|
|
r = inotify_add_watch_and_warn(m->ask_password_inotify_fd,
|
|
|
|
"/run/systemd/ask-password",
|
|
|
|
IN_CREATE|IN_DELETE|IN_MOVE);
|
|
|
|
if (r < 0) {
|
2014-10-26 02:30:51 +02:00
|
|
|
manager_close_ask_password(m);
|
2019-09-17 11:16:52 +02:00
|
|
|
return r;
|
2014-10-26 02:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_event_add_io(m->event, &m->ask_password_event_source,
|
|
|
|
m->ask_password_inotify_fd, EPOLLIN,
|
|
|
|
manager_dispatch_ask_password_fd, m);
|
|
|
|
if (r < 0) {
|
2020-04-21 17:21:38 +02:00
|
|
|
log_error_errno(r, "Failed to add event source for /run/systemd/ask-password: %m");
|
2014-10-26 02:30:51 +02:00
|
|
|
manager_close_ask_password(m);
|
2020-04-21 17:21:38 +02:00
|
|
|
return r;
|
2014-10-26 02:30:51 +02:00
|
|
|
}
|
|
|
|
|
2015-04-29 16:05:32 +02:00
|
|
|
(void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
|
|
|
|
|
2014-10-26 02:30:51 +02:00
|
|
|
/* Queries might have been added meanwhile... */
|
|
|
|
manager_dispatch_ask_password_fd(m->ask_password_event_source,
|
|
|
|
m->ask_password_inotify_fd, EPOLLIN, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
return m->have_ask_password;
|
|
|
|
}
|
|
|
|
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
static int manager_watch_idle_pipe(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (m->idle_pipe_event_source)
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (m->idle_pipe[2] < 0)
|
|
|
|
return 0;
|
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to watch idle pipe: %m");
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
|
2015-04-29 16:05:32 +02:00
|
|
|
(void) sd_event_source_set_description(m->idle_pipe_event_source, "manager-idle-pipe");
|
|
|
|
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static void manager_close_idle_pipe(Manager *m) {
|
|
|
|
assert(m);
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
|
2015-09-11 18:15:58 +02:00
|
|
|
m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
|
|
|
|
|
2014-03-24 03:22:44 +01:00
|
|
|
safe_close_pair(m->idle_pipe);
|
|
|
|
safe_close_pair(m->idle_pipe + 2);
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
}
|
|
|
|
|
2012-11-25 00:32:40 +01:00
|
|
|
static int manager_setup_time_change(Manager *m) {
|
2013-11-19 21:12:59 +01:00
|
|
|
int r;
|
2013-03-25 00:59:00 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m);
|
2012-11-25 00:32:40 +01:00
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2014-01-07 14:41:24 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-05-28 21:32:03 +02:00
|
|
|
m->time_change_event_source = sd_event_source_unref(m->time_change_event_source);
|
|
|
|
m->time_change_fd = safe_close(m->time_change_fd);
|
|
|
|
|
2018-05-29 12:55:33 +02:00
|
|
|
m->time_change_fd = time_change_fd();
|
2014-11-28 19:57:32 +01:00
|
|
|
if (m->time_change_fd < 0)
|
2018-05-29 12:55:33 +02:00
|
|
|
return log_error_errno(m->time_change_fd, "Failed to create timer change timer fd: %m");
|
2012-11-25 00:32:40 +01:00
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create time change event source: %m");
|
2012-11-25 00:32:40 +01:00
|
|
|
|
2018-05-29 16:26:24 +02:00
|
|
|
/* Schedule this slightly earlier than the .timer event sources */
|
|
|
|
r = sd_event_source_set_priority(m->time_change_event_source, SD_EVENT_PRIORITY_NORMAL-1);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set priority of time change event sources: %m");
|
|
|
|
|
2015-04-29 16:05:32 +02:00
|
|
|
(void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
|
|
|
|
|
2012-11-25 00:32:40 +01:00
|
|
|
log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-28 21:33:10 +02:00
|
|
|
static int manager_read_timezone_stat(Manager *m) {
|
|
|
|
struct stat st;
|
|
|
|
bool changed;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Read the current stat() data of /etc/localtime so that we detect changes */
|
|
|
|
if (lstat("/etc/localtime", &st) < 0) {
|
|
|
|
log_debug_errno(errno, "Failed to stat /etc/localtime, ignoring: %m");
|
|
|
|
changed = m->etc_localtime_accessible;
|
|
|
|
m->etc_localtime_accessible = false;
|
|
|
|
} else {
|
|
|
|
usec_t k;
|
|
|
|
|
|
|
|
k = timespec_load(&st.st_mtim);
|
|
|
|
changed = !m->etc_localtime_accessible || k != m->etc_localtime_mtime;
|
|
|
|
|
|
|
|
m->etc_localtime_mtime = k;
|
|
|
|
m->etc_localtime_accessible = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_setup_timezone_change(Manager *m) {
|
2018-05-29 16:26:24 +02:00
|
|
|
_cleanup_(sd_event_source_unrefp) sd_event_source *new_event = NULL;
|
2018-05-28 21:33:10 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2018-05-28 21:33:10 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* We watch /etc/localtime for three events: change of the link count (which might mean removal from /etc even
|
|
|
|
* though another link might be kept), renames, and file close operations after writing. Note we don't bother
|
|
|
|
* with IN_DELETE_SELF, as that would just report when the inode is removed entirely, i.e. after the link count
|
|
|
|
* went to zero and all fds to it are closed.
|
|
|
|
*
|
|
|
|
* Note that we never follow symlinks here. This is a simplification, but should cover almost all cases
|
|
|
|
* correctly.
|
|
|
|
*
|
|
|
|
* Note that we create the new event source first here, before releasing the old one. This should optimize
|
|
|
|
* behaviour as this way sd-event can reuse the old watch in case the inode didn't change. */
|
|
|
|
|
|
|
|
r = sd_event_add_inotify(m->event, &new_event, "/etc/localtime",
|
|
|
|
IN_ATTRIB|IN_MOVE_SELF|IN_CLOSE_WRITE|IN_DONT_FOLLOW, manager_dispatch_timezone_change, m);
|
2018-10-13 15:12:16 +02:00
|
|
|
if (r == -ENOENT) {
|
|
|
|
/* If the file doesn't exist yet, subscribe to /etc instead, and wait until it is created either by
|
|
|
|
* O_CREATE or by rename() */
|
|
|
|
|
|
|
|
log_debug_errno(r, "/etc/localtime doesn't exist yet, watching /etc instead.");
|
2018-05-28 21:33:10 +02:00
|
|
|
r = sd_event_add_inotify(m->event, &new_event, "/etc",
|
|
|
|
IN_CREATE|IN_MOVED_TO|IN_ONLYDIR, manager_dispatch_timezone_change, m);
|
2018-10-13 15:12:16 +02:00
|
|
|
}
|
2018-05-28 21:33:10 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to create timezone change event source: %m");
|
|
|
|
|
2018-05-29 16:26:24 +02:00
|
|
|
/* Schedule this slightly earlier than the .timer event sources */
|
|
|
|
r = sd_event_source_set_priority(new_event, SD_EVENT_PRIORITY_NORMAL-1);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set priority of timezone change event sources: %m");
|
|
|
|
|
2018-05-28 21:33:10 +02:00
|
|
|
sd_event_source_unref(m->timezone_change_event_source);
|
2018-05-29 16:26:24 +02:00
|
|
|
m->timezone_change_event_source = TAKE_PTR(new_event);
|
2018-05-28 21:33:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-13 02:06:27 +02:00
|
|
|
static int enable_special_signals(Manager *m) {
|
2013-11-19 21:12:59 +01:00
|
|
|
_cleanup_close_ int fd = -1;
|
2010-04-13 02:06:27 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2016-01-04 19:39:55 +01:00
|
|
|
return 0;
|
|
|
|
|
2012-04-13 16:53:49 +02:00
|
|
|
/* Enable that we get SIGINT on control-alt-del. In containers
|
2012-09-17 18:28:40 +02:00
|
|
|
* this will fail with EPERM (older) or EINVAL (newer), so
|
|
|
|
* ignore that. */
|
2017-10-04 16:01:32 +02:00
|
|
|
if (reboot(RB_DISABLE_CAD) < 0 && !IN_SET(errno, EPERM, EINVAL))
|
2014-11-28 19:29:59 +01:00
|
|
|
log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
|
2010-04-13 02:06:27 +02:00
|
|
|
|
2012-04-13 16:53:49 +02:00
|
|
|
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
|
|
|
if (fd < 0) {
|
|
|
|
/* Support systems without virtual console */
|
|
|
|
if (fd != -ENOENT)
|
2014-11-28 19:29:59 +01:00
|
|
|
log_warning_errno(errno, "Failed to open /dev/tty0: %m");
|
2012-04-13 16:53:49 +02:00
|
|
|
} else {
|
2010-04-13 02:06:27 +02:00
|
|
|
/* Enable that we get SIGWINCH on kbrequest */
|
|
|
|
if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
|
2014-11-28 19:29:59 +01:00
|
|
|
log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
|
2010-04-13 02:06:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-09 09:32:03 +01:00
|
|
|
#define RTSIG_IF_AVAILABLE(signum) (signum <= SIGRTMAX ? signum : -1)
|
|
|
|
|
2010-01-28 02:01:15 +01:00
|
|
|
static int manager_setup_signals(Manager *m) {
|
2013-03-25 00:59:00 +01:00
|
|
|
struct sigaction sa = {
|
|
|
|
.sa_handler = SIG_DFL,
|
|
|
|
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
|
|
|
|
};
|
2013-11-19 21:12:59 +01:00
|
|
|
sigset_t mask;
|
|
|
|
int r;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2010-01-28 02:01:15 +01:00
|
|
|
assert(m);
|
|
|
|
|
2010-04-13 02:36:56 +02:00
|
|
|
assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
|
|
|
|
|
2014-10-24 13:44:45 +02:00
|
|
|
/* We make liberal use of realtime signals here. On
|
|
|
|
* Linux/glibc we have 30 of them (with the exception of Linux
|
|
|
|
* on hppa, see below), between SIGRTMIN+0 ... SIGRTMIN+30
|
|
|
|
* (aka SIGRTMAX). */
|
2010-06-17 23:22:56 +02:00
|
|
|
|
2014-10-24 13:44:45 +02:00
|
|
|
assert_se(sigemptyset(&mask) == 0);
|
2010-06-17 23:22:56 +02:00
|
|
|
sigset_add_many(&mask,
|
|
|
|
SIGCHLD, /* Child died */
|
|
|
|
SIGTERM, /* Reexecute daemon */
|
|
|
|
SIGHUP, /* Reload configuration */
|
|
|
|
SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
|
|
|
|
SIGUSR2, /* systemd: dump status */
|
|
|
|
SIGINT, /* Kernel sends us this on control-alt-del */
|
|
|
|
SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
|
|
|
|
SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
|
2014-10-24 13:44:45 +02:00
|
|
|
|
2010-06-17 23:22:56 +02:00
|
|
|
SIGRTMIN+0, /* systemd: start default.target */
|
2010-10-14 00:54:48 +02:00
|
|
|
SIGRTMIN+1, /* systemd: isolate rescue.target */
|
2010-06-17 23:22:56 +02:00
|
|
|
SIGRTMIN+2, /* systemd: isolate emergency.target */
|
|
|
|
SIGRTMIN+3, /* systemd: start halt.target */
|
|
|
|
SIGRTMIN+4, /* systemd: start poweroff.target */
|
|
|
|
SIGRTMIN+5, /* systemd: start reboot.target */
|
2010-10-14 00:54:48 +02:00
|
|
|
SIGRTMIN+6, /* systemd: start kexec.target */
|
2014-10-24 13:44:45 +02:00
|
|
|
|
|
|
|
/* ... space for more special targets ... */
|
|
|
|
|
2010-10-14 00:54:48 +02:00
|
|
|
SIGRTMIN+13, /* systemd: Immediate halt */
|
|
|
|
SIGRTMIN+14, /* systemd: Immediate poweroff */
|
|
|
|
SIGRTMIN+15, /* systemd: Immediate reboot */
|
|
|
|
SIGRTMIN+16, /* systemd: Immediate kexec */
|
2014-10-24 13:44:45 +02:00
|
|
|
|
|
|
|
/* ... space for more immediate system state changes ... */
|
|
|
|
|
2011-02-09 12:12:30 +01:00
|
|
|
SIGRTMIN+20, /* systemd: enable status messages */
|
|
|
|
SIGRTMIN+21, /* systemd: disable status messages */
|
2011-07-23 04:15:38 +02:00
|
|
|
SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
|
|
|
|
SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
|
2012-10-18 01:19:35 +02:00
|
|
|
SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
|
2014-10-24 13:44:45 +02:00
|
|
|
|
|
|
|
/* .. one free signal here ... */
|
|
|
|
|
2018-03-09 09:32:03 +01:00
|
|
|
/* Apparently Linux on hppa had fewer RT signals until v3.18,
|
|
|
|
* SIGRTMAX was SIGRTMIN+25, and then SIGRTMIN was lowered,
|
|
|
|
* see commit v3.17-7614-g1f25df2eff.
|
|
|
|
*
|
|
|
|
* We cannot unconditionally make use of those signals here,
|
|
|
|
* so let's use a runtime check. Since these commands are
|
|
|
|
* accessible by different means and only really a safety
|
|
|
|
* net, the missing functionality on hppa shouldn't matter.
|
|
|
|
*/
|
|
|
|
|
|
|
|
RTSIG_IF_AVAILABLE(SIGRTMIN+26), /* systemd: set log target to journal-or-kmsg */
|
|
|
|
RTSIG_IF_AVAILABLE(SIGRTMIN+27), /* systemd: set log target to console */
|
|
|
|
RTSIG_IF_AVAILABLE(SIGRTMIN+28), /* systemd: set log target to kmsg */
|
|
|
|
RTSIG_IF_AVAILABLE(SIGRTMIN+29), /* systemd: set log target to syslog-or-kmsg (obsolete) */
|
2014-10-24 13:44:45 +02:00
|
|
|
|
|
|
|
/* ... one free signal here SIGRTMIN+30 ... */
|
2010-06-17 23:22:56 +02:00
|
|
|
-1);
|
2010-01-28 02:01:15 +01:00
|
|
|
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
|
|
|
if (m->signal_fd < 0)
|
2010-01-28 02:01:15 +01:00
|
|
|
return -errno;
|
|
|
|
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m);
|
2013-11-19 21:12:59 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-01-28 02:01:15 +01:00
|
|
|
|
2015-04-29 16:05:32 +02:00
|
|
|
(void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
|
|
|
|
|
2016-05-04 20:43:23 +02:00
|
|
|
/* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the
|
|
|
|
* notify processing can still figure out to which process/service a message belongs, before we reap the
|
|
|
|
* process. Also, process this before handling cgroup notifications, so that we always collect child exit
|
|
|
|
* status information before detecting that there's no process in a cgroup. */
|
|
|
|
r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-6);
|
2013-11-25 15:35:10 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
2010-04-13 02:06:27 +02:00
|
|
|
return enable_special_signals(m);
|
2010-02-14 22:39:40 +01:00
|
|
|
|
2010-01-28 02:01:15 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
static char** sanitize_environment(char **l) {
|
2014-01-12 13:10:40 +01:00
|
|
|
|
2018-01-10 18:28:42 +01:00
|
|
|
/* Let's remove some environment variables that we need ourselves to communicate with our clients */
|
2014-01-12 13:10:40 +01:00
|
|
|
strv_env_unset_many(
|
2018-10-31 15:49:19 +01:00
|
|
|
l,
|
2020-07-23 08:48:56 +02:00
|
|
|
"CACHE_DIRECTORY",
|
|
|
|
"CONFIGURATION_DIRECTORY",
|
2020-07-23 08:49:52 +02:00
|
|
|
"CREDENTIALS_DIRECTORY",
|
2018-01-10 18:28:42 +01:00
|
|
|
"EXIT_CODE",
|
|
|
|
"EXIT_STATUS",
|
|
|
|
"INVOCATION_ID",
|
|
|
|
"JOURNAL_STREAM",
|
|
|
|
"LISTEN_FDNAMES",
|
|
|
|
"LISTEN_FDS",
|
|
|
|
"LISTEN_PID",
|
2020-07-23 08:48:56 +02:00
|
|
|
"LOGS_DIRECTORY",
|
2014-01-12 13:10:40 +01:00
|
|
|
"MAINPID",
|
|
|
|
"MANAGERPID",
|
2018-01-10 18:28:42 +01:00
|
|
|
"NOTIFY_SOCKET",
|
2019-01-30 17:39:09 +01:00
|
|
|
"PIDFILE",
|
2018-01-10 18:28:42 +01:00
|
|
|
"REMOTE_ADDR",
|
|
|
|
"REMOTE_PORT",
|
2020-07-23 08:48:56 +02:00
|
|
|
"RUNTIME_DIRECTORY",
|
2018-01-10 18:28:42 +01:00
|
|
|
"SERVICE_RESULT",
|
2020-07-23 08:48:56 +02:00
|
|
|
"STATE_DIRECTORY",
|
2014-01-12 13:10:40 +01:00
|
|
|
"WATCHDOG_PID",
|
|
|
|
"WATCHDOG_USEC",
|
|
|
|
NULL);
|
2018-01-10 18:28:42 +01:00
|
|
|
|
|
|
|
/* Let's order the environment alphabetically, just to make it pretty */
|
2018-10-31 15:49:19 +01:00
|
|
|
strv_sort(l);
|
|
|
|
|
|
|
|
return l;
|
2014-01-12 13:10:40 +01:00
|
|
|
}
|
|
|
|
|
2018-11-19 12:23:13 +01:00
|
|
|
int manager_default_environment(Manager *m) {
|
2015-08-07 03:34:15 +02:00
|
|
|
int r;
|
|
|
|
|
2012-04-11 12:56:51 +02:00
|
|
|
assert(m);
|
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
m->transient_environment = strv_free(m->transient_environment);
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m)) {
|
2013-07-26 05:22:22 +02:00
|
|
|
/* The system manager always starts with a clean
|
|
|
|
* environment for its children. It does not import
|
2017-02-10 21:41:42 +01:00
|
|
|
* the kernel's or the parents' exported variables.
|
2013-07-26 05:22:22 +02:00
|
|
|
*
|
2017-02-10 21:41:42 +01:00
|
|
|
* The initial passed environment is untouched to keep
|
2013-07-26 05:22:22 +02:00
|
|
|
* /proc/self/environ valid; it is used for tagging
|
|
|
|
* the init process inside containers. */
|
2018-10-31 15:49:19 +01:00
|
|
|
m->transient_environment = strv_new("PATH=" DEFAULT_PATH);
|
2015-08-07 03:34:15 +02:00
|
|
|
if (!m->transient_environment)
|
|
|
|
return log_oom();
|
2013-07-26 05:22:22 +02:00
|
|
|
|
|
|
|
/* Import locale variables LC_*= from configuration */
|
2018-10-31 15:49:19 +01:00
|
|
|
(void) locale_setup(&m->transient_environment);
|
2015-08-07 03:34:15 +02:00
|
|
|
} else {
|
|
|
|
_cleanup_free_ char *k = NULL;
|
|
|
|
|
2013-07-26 05:22:22 +02:00
|
|
|
/* The user manager passes its own environment
|
2015-08-07 03:34:15 +02:00
|
|
|
* along to its children, except for $PATH. */
|
2018-10-31 15:49:19 +01:00
|
|
|
m->transient_environment = strv_copy(environ);
|
2015-08-07 03:34:15 +02:00
|
|
|
if (!m->transient_environment)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
k = strdup("PATH=" DEFAULT_USER_PATH);
|
|
|
|
if (!k)
|
|
|
|
return log_oom();
|
2014-01-12 12:39:56 +01:00
|
|
|
|
2015-08-07 03:34:15 +02:00
|
|
|
r = strv_env_replace(&m->transient_environment, k);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
TAKE_PTR(k);
|
|
|
|
}
|
2013-02-11 23:53:14 +01:00
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
sanitize_environment(m->transient_environment);
|
2013-11-21 19:31:46 +01:00
|
|
|
|
2013-07-26 05:22:22 +02:00
|
|
|
return 0;
|
2012-04-11 12:56:51 +02:00
|
|
|
}
|
|
|
|
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
static int manager_setup_prefix(Manager *m) {
|
|
|
|
struct table_entry {
|
|
|
|
uint64_t type;
|
|
|
|
const char *suffix;
|
|
|
|
};
|
|
|
|
|
2017-09-28 16:58:43 +02:00
|
|
|
static const struct table_entry paths_system[_EXEC_DIRECTORY_TYPE_MAX] = {
|
2020-09-04 17:34:11 +02:00
|
|
|
[EXEC_DIRECTORY_RUNTIME] = { SD_PATH_SYSTEM_RUNTIME, NULL },
|
|
|
|
[EXEC_DIRECTORY_STATE] = { SD_PATH_SYSTEM_STATE_PRIVATE, NULL },
|
|
|
|
[EXEC_DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE, NULL },
|
|
|
|
[EXEC_DIRECTORY_LOGS] = { SD_PATH_SYSTEM_STATE_LOGS, NULL },
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
[EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_SYSTEM_CONFIGURATION, NULL },
|
|
|
|
};
|
|
|
|
|
2017-09-28 16:58:43 +02:00
|
|
|
static const struct table_entry paths_user[_EXEC_DIRECTORY_TYPE_MAX] = {
|
2020-09-04 17:34:11 +02:00
|
|
|
[EXEC_DIRECTORY_RUNTIME] = { SD_PATH_USER_RUNTIME, NULL },
|
|
|
|
[EXEC_DIRECTORY_STATE] = { SD_PATH_USER_CONFIGURATION, NULL },
|
|
|
|
[EXEC_DIRECTORY_CACHE] = { SD_PATH_USER_STATE_CACHE, NULL },
|
|
|
|
[EXEC_DIRECTORY_LOGS] = { SD_PATH_USER_CONFIGURATION, "log" },
|
|
|
|
[EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_USER_CONFIGURATION, NULL },
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-05-26 19:28:53 +02:00
|
|
|
const struct table_entry *p = MANAGER_IS_SYSTEM(m) ? paths_system : paths_user;
|
|
|
|
int r;
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
|
2020-05-26 19:28:53 +02:00
|
|
|
for (ExecDirectoryType i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
|
2020-03-23 19:50:59 +01:00
|
|
|
r = sd_path_lookup(p[i].type, p[i].suffix, &m->prefix[i]);
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-18 13:11:28 +02:00
|
|
|
static void manager_free_unit_name_maps(Manager *m) {
|
|
|
|
m->unit_id_map = hashmap_free(m->unit_id_map);
|
|
|
|
m->unit_name_map = hashmap_free(m->unit_name_map);
|
2020-05-28 14:58:35 +02:00
|
|
|
m->unit_path_cache = set_free(m->unit_path_cache);
|
2020-08-28 12:21:48 +02:00
|
|
|
m->unit_cache_timestamp_hash = 0;
|
2019-07-18 13:11:28 +02:00
|
|
|
}
|
|
|
|
|
2017-12-06 23:24:00 +01:00
|
|
|
static int manager_setup_run_queue(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(!m->run_queue_event_source);
|
|
|
|
|
|
|
|
r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->run_queue_event_source, "manager-run-queue");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
static int manager_setup_sigchld_event_source(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(!m->sigchld_event_source);
|
|
|
|
|
|
|
|
r = sd_event_add_defer(m->event, &m->sigchld_event_source, manager_dispatch_sigchld, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_priority(m->sigchld_event_source, SD_EVENT_PRIORITY_NORMAL-7);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_event_source_set_enabled(m->sigchld_event_source, SD_EVENT_OFF);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->sigchld_event_source, "manager-sigchld");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
|
2018-03-09 21:55:55 +01:00
|
|
|
_cleanup_(manager_freep) Manager *m = NULL;
|
2020-07-23 08:49:52 +02:00
|
|
|
const char *e;
|
2013-11-30 03:53:42 +01:00
|
|
|
int r;
|
2010-03-31 16:29:55 +02:00
|
|
|
|
|
|
|
assert(_m);
|
2016-02-24 21:24:23 +01:00
|
|
|
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER));
|
2010-01-28 02:01:15 +01:00
|
|
|
|
2018-10-09 15:54:10 +02:00
|
|
|
m = new(Manager, 1);
|
2012-09-13 18:54:32 +02:00
|
|
|
if (!m)
|
2010-03-31 16:29:55 +02:00
|
|
|
return -ENOMEM;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2018-10-09 15:54:10 +02:00
|
|
|
*m = (Manager) {
|
|
|
|
.unit_file_scope = scope,
|
|
|
|
.objective = _MANAGER_OBJECTIVE_INVALID,
|
|
|
|
|
2019-06-06 19:22:20 +02:00
|
|
|
.status_unit_format = STATUS_UNIT_FORMAT_DEFAULT,
|
|
|
|
|
2018-10-09 15:54:10 +02:00
|
|
|
.default_timer_accuracy_usec = USEC_PER_MINUTE,
|
|
|
|
.default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT,
|
|
|
|
.default_tasks_accounting = true,
|
2019-11-05 13:50:28 +01:00
|
|
|
.default_tasks_max = TASKS_MAX_UNSET,
|
2018-10-09 15:54:10 +02:00
|
|
|
.default_timeout_start_usec = DEFAULT_TIMEOUT_USEC,
|
|
|
|
.default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC,
|
|
|
|
.default_restart_usec = DEFAULT_RESTART_USEC,
|
|
|
|
|
|
|
|
.original_log_level = -1,
|
|
|
|
.original_log_target = _LOG_TARGET_INVALID,
|
|
|
|
|
2020-04-22 16:16:47 +02:00
|
|
|
.watchdog_overridden[WATCHDOG_RUNTIME] = USEC_INFINITY,
|
|
|
|
.watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
|
|
|
|
.watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
.show_status_overridden = _SHOW_STATUS_INVALID,
|
|
|
|
|
2018-10-09 15:54:10 +02:00
|
|
|
.notify_fd = -1,
|
|
|
|
.cgroups_agent_fd = -1,
|
|
|
|
.signal_fd = -1,
|
|
|
|
.time_change_fd = -1,
|
|
|
|
.user_lookup_fds = { -1, -1 },
|
|
|
|
.private_listen_fd = -1,
|
|
|
|
.dev_autofs_fd = -1,
|
|
|
|
.cgroup_inotify_fd = -1,
|
|
|
|
.pin_cgroupfs_fd = -1,
|
|
|
|
.ask_password_inotify_fd = -1,
|
|
|
|
.idle_pipe = { -1, -1, -1, -1},
|
|
|
|
|
|
|
|
/* start as id #1, so that we can leave #0 around as "null-like" value */
|
|
|
|
.current_job_id = 1,
|
|
|
|
|
|
|
|
.have_ask_password = -EINVAL, /* we don't know */
|
|
|
|
.first_boot = -1,
|
|
|
|
.test_run_flags = test_run_flags,
|
2019-03-19 19:05:19 +01:00
|
|
|
|
|
|
|
.default_oom_policy = OOM_STOP,
|
2018-10-09 15:54:10 +02:00
|
|
|
};
|
2010-04-13 02:06:27 +02:00
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if ENABLE_EFI
|
2016-02-24 21:24:23 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
|
2017-11-20 21:01:13 +01:00
|
|
|
boot_timestamps(m->timestamps + MANAGER_TIMESTAMP_USERSPACE,
|
|
|
|
m->timestamps + MANAGER_TIMESTAMP_FIRMWARE,
|
|
|
|
m->timestamps + MANAGER_TIMESTAMP_LOADER);
|
2016-02-24 21:24:23 +01:00
|
|
|
#endif
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
/* Prepare log fields we can use for structured logging */
|
2016-02-24 21:24:23 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m)) {
|
|
|
|
m->unit_log_field = "UNIT=";
|
|
|
|
m->unit_log_format_string = "UNIT=%s";
|
2016-08-30 23:18:46 +02:00
|
|
|
|
|
|
|
m->invocation_log_field = "INVOCATION_ID=";
|
2017-09-20 18:27:53 +02:00
|
|
|
m->invocation_log_format_string = "INVOCATION_ID=%s";
|
2016-02-24 21:24:23 +01:00
|
|
|
} else {
|
|
|
|
m->unit_log_field = "USER_UNIT=";
|
|
|
|
m->unit_log_format_string = "USER_UNIT=%s";
|
2016-08-30 23:18:46 +02:00
|
|
|
|
|
|
|
m->invocation_log_field = "USER_INVOCATION_ID=";
|
2017-09-20 18:27:53 +02:00
|
|
|
m->invocation_log_format_string = "USER_INVOCATION_ID=%s";
|
2016-02-24 21:24:23 +01:00
|
|
|
}
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
|
2015-01-28 02:18:59 +01:00
|
|
|
/* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
|
2019-09-19 17:41:20 +02:00
|
|
|
m->ctrl_alt_del_ratelimit = (RateLimit) { .interval = 2 * USEC_PER_SEC, .burst = 7 };
|
2015-01-28 02:18:59 +01:00
|
|
|
|
2013-07-26 05:22:22 +02:00
|
|
|
r = manager_default_environment(m);
|
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2010-05-09 23:53:52 +02:00
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
r = hashmap_ensure_allocated(&m->units, &string_hash_ops);
|
2013-11-19 21:12:59 +01:00
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2018-02-08 18:58:35 +01:00
|
|
|
r = hashmap_ensure_allocated(&m->cgroup_unit, &path_hash_ops);
|
2013-11-19 21:12:59 +01:00
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops);
|
2013-11-19 21:12:59 +01:00
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2010-04-15 23:16:16 +02:00
|
|
|
|
2019-05-22 12:12:17 +02:00
|
|
|
r = prioq_ensure_allocated(&m->run_queue, compare_job_priority);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
r = manager_setup_prefix(m);
|
2013-11-19 21:12:59 +01:00
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2012-11-25 00:32:40 +01:00
|
|
|
|
2020-07-23 08:49:52 +02:00
|
|
|
e = secure_getenv("CREDENTIALS_DIRECTORY");
|
|
|
|
if (e) {
|
|
|
|
m->received_credentials = strdup(e);
|
|
|
|
if (!m->received_credentials)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
r = sd_event_default(&m->event);
|
2012-11-25 00:32:40 +01:00
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
r = manager_setup_run_queue(m);
|
2018-03-08 07:29:19 +01:00
|
|
|
if (r < 0)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
2010-03-31 16:29:55 +02:00
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
if (test_run_flags == MANAGER_TEST_RUN_MINIMAL) {
|
|
|
|
m->cgroup_root = strdup("");
|
|
|
|
if (!m->cgroup_root)
|
|
|
|
return -ENOMEM;
|
|
|
|
} else {
|
|
|
|
r = manager_setup_signals(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-06-16 05:10:31 +02:00
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
r = manager_setup_cgroup(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-01-23 18:18:13 +01:00
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
r = manager_setup_time_change(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-11-25 21:08:39 +01:00
|
|
|
|
2018-05-28 21:33:10 +02:00
|
|
|
r = manager_read_timezone_stat(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-10-13 15:12:41 +02:00
|
|
|
(void) manager_setup_timezone_change(m);
|
2018-05-28 21:33:10 +02:00
|
|
|
|
2018-03-10 11:02:18 +01:00
|
|
|
r = manager_setup_sigchld_event_source(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2017-12-07 11:09:09 +01:00
|
|
|
|
2019-12-12 06:15:42 +01:00
|
|
|
if (test_run_flags == 0) {
|
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
r = mkdir_label("/run/systemd/units", 0755);
|
|
|
|
else {
|
|
|
|
_cleanup_free_ char *units_path = NULL;
|
|
|
|
r = xdg_user_runtime_dir(&units_path, "/systemd/units");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = mkdir_p_label(units_path, 0755);
|
|
|
|
}
|
|
|
|
|
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
|
|
|
if (r < 0 && r != -EEXIST)
|
2018-03-09 21:55:55 +01:00
|
|
|
return r;
|
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
|
|
|
}
|
|
|
|
|
2017-12-07 11:09:09 +01:00
|
|
|
m->taint_usr =
|
|
|
|
!in_initrd() &&
|
|
|
|
dir_is_empty("/usr") > 0;
|
|
|
|
|
2016-09-09 16:16:26 +02:00
|
|
|
/* Note that we do not set up the notify fd here. We do that after deserialization,
|
|
|
|
* since they might have gotten serialized across the reexec. */
|
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*_m = TAKE_PTR(m);
|
|
|
|
|
2010-03-31 16:29:55 +02:00
|
|
|
return 0;
|
2009-11-18 00:42:52 +01:00
|
|
|
}
|
|
|
|
|
2013-12-21 00:19:37 +01:00
|
|
|
static int manager_setup_notify(Manager *m) {
|
2014-03-19 22:46:45 +01:00
|
|
|
int r;
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2014-01-07 14:41:24 +01:00
|
|
|
return 0;
|
|
|
|
|
2013-12-21 00:19:37 +01:00
|
|
|
if (m->notify_fd < 0) {
|
|
|
|
_cleanup_close_ int fd = -1;
|
2020-03-02 15:51:31 +01:00
|
|
|
union sockaddr_union sa;
|
|
|
|
socklen_t sa_len;
|
2013-12-21 00:19:37 +01:00
|
|
|
|
|
|
|
/* First free all secondary fields */
|
2015-09-08 18:43:11 +02:00
|
|
|
m->notify_socket = mfree(m->notify_socket);
|
2013-12-21 00:19:37 +01:00
|
|
|
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
|
|
|
|
|
|
|
|
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
2014-11-28 19:57:32 +01:00
|
|
|
if (fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to allocate notification socket: %m");
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2015-10-30 11:27:29 +01:00
|
|
|
fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
m->notify_socket = path_join(m->prefix[EXEC_DIRECTORY_RUNTIME], "systemd/notify");
|
2014-11-07 02:05:50 +01:00
|
|
|
if (!m->notify_socket)
|
|
|
|
return log_oom();
|
|
|
|
|
2020-03-02 15:51:31 +01:00
|
|
|
r = sockaddr_un_set_path(&sa.un, m->notify_socket);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Notify socket '%s' not valid for AF_UNIX socket address, refusing.",
|
|
|
|
m->notify_socket);
|
|
|
|
sa_len = r;
|
2018-10-15 13:58:31 +02:00
|
|
|
|
2014-11-07 02:05:50 +01:00
|
|
|
(void) mkdir_parents_label(m->notify_socket, 0755);
|
2018-10-15 19:40:18 +02:00
|
|
|
(void) sockaddr_un_unlink(&sa.un);
|
2014-03-19 22:46:45 +01:00
|
|
|
|
2020-09-01 15:49:20 +02:00
|
|
|
r = mac_selinux_bind(fd, &sa.sa, sa_len);
|
2014-11-28 19:57:32 +01:00
|
|
|
if (r < 0)
|
2020-09-01 15:49:20 +02:00
|
|
|
return log_error_errno(r, "bind(%s) failed: %m", m->notify_socket);
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2018-10-18 19:48:18 +02:00
|
|
|
r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
|
2014-11-28 19:57:32 +01:00
|
|
|
if (r < 0)
|
2018-10-18 19:48:18 +02:00
|
|
|
return log_error_errno(r, "SO_PASSCRED failed: %m");
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2018-03-22 17:04:29 +01:00
|
|
|
m->notify_fd = TAKE_FD(fd);
|
2013-12-21 00:19:37 +01:00
|
|
|
|
|
|
|
log_debug("Using notification socket %s", m->notify_socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m->notify_event_source) {
|
2014-02-19 23:54:58 +01:00
|
|
|
r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m);
|
2014-11-28 19:20:59 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate notify event source: %m");
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2016-05-04 20:43:23 +02:00
|
|
|
/* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which
|
|
|
|
* service an exit message belongs. */
|
2018-01-23 18:18:13 +01:00
|
|
|
r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-8);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set priority of notify event source: %m");
|
2015-04-29 16:05:32 +02:00
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->notify_event_source, "manager-notify");
|
2013-12-21 00:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-04 20:43:23 +02:00
|
|
|
static int manager_setup_cgroups_agent(Manager *m) {
|
|
|
|
|
|
|
|
static const union sockaddr_union sa = {
|
|
|
|
.un.sun_family = AF_UNIX,
|
|
|
|
.un.sun_path = "/run/systemd/cgroups-agent",
|
|
|
|
};
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
|
|
|
|
* these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
|
|
|
|
* each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
|
|
|
|
* overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
|
|
|
|
* of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
|
|
|
|
* possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
|
|
|
|
* socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
|
|
|
|
* we thus won't lose messages.
|
|
|
|
*
|
|
|
|
* Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
|
|
|
|
* to it. The system instance hence listens on this special socket, but the user instances listen on the system
|
|
|
|
* bus for these messages. */
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2016-05-04 20:43:23 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
|
|
|
return 0;
|
|
|
|
|
2017-02-24 18:00:04 +01:00
|
|
|
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
2017-02-24 17:52:58 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to determine whether unified cgroups hierarchy is used: %m");
|
|
|
|
if (r > 0) /* We don't need this anymore on the unified hierarchy */
|
2016-05-04 20:43:23 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (m->cgroups_agent_fd < 0) {
|
|
|
|
_cleanup_close_ int fd = -1;
|
|
|
|
|
|
|
|
/* First free all secondary fields */
|
|
|
|
m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
|
|
|
|
|
|
|
|
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
|
|
|
|
|
|
|
|
fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE);
|
|
|
|
|
2018-10-15 12:08:30 +02:00
|
|
|
(void) sockaddr_un_unlink(&sa.un);
|
2016-05-04 20:43:23 +02:00
|
|
|
|
|
|
|
/* Only allow root to connect to this socket */
|
|
|
|
RUN_WITH_UMASK(0077)
|
2016-05-05 22:24:36 +02:00
|
|
|
r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
|
2016-05-04 20:43:23 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
|
|
|
|
|
2018-10-15 12:09:17 +02:00
|
|
|
m->cgroups_agent_fd = TAKE_FD(fd);
|
2016-05-04 20:43:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!m->cgroups_agent_event_source) {
|
|
|
|
r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
|
|
|
|
|
2019-03-18 20:21:11 +01:00
|
|
|
/* Process cgroups notifications early. Note that when the agent notification is received
|
|
|
|
* we'll just enqueue the unit in the cgroup empty queue, hence pick a high priority than
|
|
|
|
* that. Also see handling of cgroup inotify for the unified cgroup stuff. */
|
|
|
|
r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-9);
|
2016-05-04 20:43:23 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
|
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
static int manager_setup_user_lookup_fd(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Set up the socket pair used for passing UID/GID resolution results from forked off processes to PID
|
|
|
|
* 1. Background: we can't do name lookups (NSS) from PID 1, since it might involve IPC and thus activation,
|
|
|
|
* and we might hence deadlock on ourselves. Hence we do all user/group lookups asynchronously from the forked
|
|
|
|
* off processes right before executing the binaries to start. In order to be able to clean up any IPC objects
|
|
|
|
* created by a unit (see RemoveIPC=) we need to know in PID 1 the used UID/GID of the executed processes,
|
|
|
|
* hence we establish this communication channel so that forked off processes can pass their UID/GID
|
|
|
|
* information back to PID 1. The forked off processes send their resolved UID/GID to PID 1 in a simple
|
|
|
|
* datagram, along with their unit name, so that we can share one communication socket pair among all units for
|
|
|
|
* this purpose.
|
|
|
|
*
|
|
|
|
* You might wonder why we need a communication channel for this that is independent of the usual notification
|
|
|
|
* socket scheme (i.e. $NOTIFY_SOCKET). The primary difference is about trust: data sent via the $NOTIFY_SOCKET
|
|
|
|
* channel is only accepted if it originates from the right unit and if reception was enabled for it. The user
|
|
|
|
* lookup socket OTOH is only accessible by PID 1 and its children until they exec(), and always available.
|
|
|
|
*
|
|
|
|
* Note that this function is called under two circumstances: when we first initialize (in which case we
|
|
|
|
* allocate both the socket pair and the event source to listen on it), and when we deserialize after a reload
|
|
|
|
* (in which case the socket pair already exists but we still need to allocate the event source for it). */
|
|
|
|
|
|
|
|
if (m->user_lookup_fds[0] < 0) {
|
|
|
|
|
|
|
|
/* Free all secondary fields */
|
|
|
|
safe_close_pair(m->user_lookup_fds);
|
|
|
|
m->user_lookup_event_source = sd_event_source_unref(m->user_lookup_event_source);
|
|
|
|
|
|
|
|
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, m->user_lookup_fds) < 0)
|
|
|
|
return log_error_errno(errno, "Failed to allocate user lookup socket: %m");
|
|
|
|
|
|
|
|
(void) fd_inc_rcvbuf(m->user_lookup_fds[0], NOTIFY_RCVBUF_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m->user_lookup_event_source) {
|
|
|
|
r = sd_event_add_io(m->event, &m->user_lookup_event_source, m->user_lookup_fds[0], EPOLLIN, manager_dispatch_user_lookup_fd, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(errno, "Failed to allocate user lookup event source: %m");
|
|
|
|
|
|
|
|
/* Process even earlier than the notify event source, so that we always know first about valid UID/GID
|
|
|
|
* resolutions */
|
2018-01-23 18:15:16 +01:00
|
|
|
r = sd_event_source_set_priority(m->user_lookup_event_source, SD_EVENT_PRIORITY_NORMAL-11);
|
2016-08-01 19:24:40 +02:00
|
|
|
if (r < 0)
|
2019-04-27 02:22:40 +02:00
|
|
|
return log_error_errno(errno, "Failed to set priority of user lookup event source: %m");
|
2016-08-01 19:24:40 +02:00
|
|
|
|
|
|
|
(void) sd_event_source_set_description(m->user_lookup_event_source, "user-lookup");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-06 02:43:58 +02:00
|
|
|
static unsigned manager_dispatch_cleanup_queue(Manager *m) {
|
2012-01-15 12:37:16 +01:00
|
|
|
Unit *u;
|
2010-04-06 02:43:58 +02:00
|
|
|
unsigned n = 0;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
while ((u = m->cleanup_queue)) {
|
|
|
|
assert(u->in_cleanup_queue);
|
2010-04-06 02:43:58 +02:00
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
unit_free(u);
|
2010-04-06 02:43:58 +02:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2010-04-23 18:47:49 +02:00
|
|
|
enum {
|
2011-02-21 15:32:17 +01:00
|
|
|
GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
|
2010-04-23 18:47:49 +02:00
|
|
|
GC_OFFSET_UNSURE, /* No clue */
|
|
|
|
GC_OFFSET_GOOD, /* We still need this unit */
|
|
|
|
GC_OFFSET_BAD, /* We don't need this unit anymore */
|
|
|
|
_GC_OFFSET_MAX
|
|
|
|
};
|
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
static void unit_gc_mark_good(Unit *u, unsigned gc_marker) {
|
2016-06-14 14:20:56 +02:00
|
|
|
Unit *other;
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
void *v;
|
2016-06-14 14:20:56 +02:00
|
|
|
|
|
|
|
u->gc_marker = gc_marker + GC_OFFSET_GOOD;
|
|
|
|
|
|
|
|
/* Recursively mark referenced units as GOOD as well */
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCES])
|
2016-06-14 14:20:56 +02:00
|
|
|
if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
|
|
|
|
unit_gc_mark_good(other, gc_marker);
|
|
|
|
}
|
|
|
|
|
2010-04-23 18:47:49 +02:00
|
|
|
static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
|
2010-04-21 06:01:13 +02:00
|
|
|
Unit *other;
|
2010-04-23 18:47:49 +02:00
|
|
|
bool is_bad;
|
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
|
|
|
void *v;
|
2010-04-21 06:01:13 +02:00
|
|
|
|
|
|
|
assert(u);
|
|
|
|
|
2017-10-04 16:01:32 +02:00
|
|
|
if (IN_SET(u->gc_marker - gc_marker,
|
|
|
|
GC_OFFSET_GOOD, GC_OFFSET_BAD, GC_OFFSET_UNSURE, GC_OFFSET_IN_PATH))
|
2010-04-21 06:01:13 +02:00
|
|
|
return;
|
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
if (u->in_cleanup_queue)
|
2010-04-21 06:01:13 +02:00
|
|
|
goto bad;
|
|
|
|
|
2018-02-13 10:50:13 +01:00
|
|
|
if (!unit_may_gc(u))
|
2010-04-21 06:01:13 +02:00
|
|
|
goto good;
|
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
|
2010-04-23 18:47:49 +02:00
|
|
|
|
|
|
|
is_bad = true;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCED_BY]) {
|
2010-04-21 06:01:13 +02:00
|
|
|
unit_gc_sweep(other, gc_marker);
|
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
|
2010-04-21 06:01:13 +02:00
|
|
|
goto good;
|
2010-04-23 18:47:49 +02:00
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
|
2010-04-23 18:47:49 +02:00
|
|
|
is_bad = false;
|
2010-04-21 06:01:13 +02:00
|
|
|
}
|
|
|
|
|
2018-02-13 14:37:11 +01:00
|
|
|
if (u->refs_by_target) {
|
|
|
|
const UnitRef *ref;
|
|
|
|
|
|
|
|
LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
|
|
|
|
unit_gc_sweep(ref->source, gc_marker);
|
|
|
|
|
|
|
|
if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
|
|
|
|
goto good;
|
|
|
|
|
|
|
|
if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
|
|
|
|
is_bad = false;
|
|
|
|
}
|
|
|
|
}
|
2010-04-21 06:01:13 +02:00
|
|
|
|
2010-04-23 18:47:49 +02:00
|
|
|
if (is_bad)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
/* We were unable to find anything out about this entry, so
|
|
|
|
* let's investigate it later */
|
2012-01-15 12:04:08 +01:00
|
|
|
u->gc_marker = gc_marker + GC_OFFSET_UNSURE;
|
2010-04-23 18:47:49 +02:00
|
|
|
unit_add_to_gc_queue(u);
|
|
|
|
return;
|
|
|
|
|
2010-04-21 06:01:13 +02:00
|
|
|
bad:
|
2010-04-23 18:47:49 +02:00
|
|
|
/* We definitely know that this one is not useful anymore, so
|
|
|
|
* let's mark it for deletion */
|
2012-01-15 12:04:08 +01:00
|
|
|
u->gc_marker = gc_marker + GC_OFFSET_BAD;
|
2010-04-23 18:47:49 +02:00
|
|
|
unit_add_to_cleanup_queue(u);
|
2010-04-21 06:01:13 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
good:
|
2016-06-14 14:20:56 +02:00
|
|
|
unit_gc_mark_good(u, gc_marker);
|
2010-04-21 06:01:13 +02:00
|
|
|
}
|
|
|
|
|
2016-11-15 19:32:50 +01:00
|
|
|
static unsigned manager_dispatch_gc_unit_queue(Manager *m) {
|
|
|
|
unsigned n = 0, gc_marker;
|
2012-01-15 12:37:16 +01:00
|
|
|
Unit *u;
|
2010-04-21 06:01:13 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2013-07-02 17:41:57 +02:00
|
|
|
/* log_debug("Running GC..."); */
|
2010-04-21 06:01:13 +02:00
|
|
|
|
2010-04-23 18:47:49 +02:00
|
|
|
m->gc_marker += _GC_OFFSET_MAX;
|
|
|
|
if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
|
2010-04-22 02:41:14 +02:00
|
|
|
m->gc_marker = 1;
|
2010-04-21 06:01:13 +02:00
|
|
|
|
2010-04-23 18:47:49 +02:00
|
|
|
gc_marker = m->gc_marker;
|
|
|
|
|
2016-11-15 19:32:50 +01:00
|
|
|
while ((u = m->gc_unit_queue)) {
|
2012-01-15 12:37:16 +01:00
|
|
|
assert(u->in_gc_queue);
|
2010-04-21 06:01:13 +02:00
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
unit_gc_sweep(u, gc_marker);
|
2010-04-23 18:47:49 +02:00
|
|
|
|
2016-11-15 19:32:50 +01:00
|
|
|
LIST_REMOVE(gc_queue, m->gc_unit_queue, u);
|
2012-01-15 12:37:16 +01:00
|
|
|
u->in_gc_queue = false;
|
2010-04-21 06:01:13 +02:00
|
|
|
|
|
|
|
n++;
|
|
|
|
|
2017-10-04 16:01:32 +02:00
|
|
|
if (IN_SET(u->gc_marker - gc_marker,
|
|
|
|
GC_OFFSET_BAD, GC_OFFSET_UNSURE)) {
|
2015-03-15 17:12:19 +01:00
|
|
|
if (u->id)
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(u, "Collecting.");
|
2012-01-15 12:37:16 +01:00
|
|
|
u->gc_marker = gc_marker + GC_OFFSET_BAD;
|
|
|
|
unit_add_to_cleanup_queue(u);
|
2010-04-21 06:01:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2016-11-15 19:32:50 +01:00
|
|
|
static unsigned manager_dispatch_gc_job_queue(Manager *m) {
|
|
|
|
unsigned n = 0;
|
|
|
|
Job *j;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
while ((j = m->gc_job_queue)) {
|
|
|
|
assert(j->in_gc_queue);
|
|
|
|
|
|
|
|
LIST_REMOVE(gc_queue, m->gc_job_queue, j);
|
|
|
|
j->in_gc_queue = false;
|
|
|
|
|
|
|
|
n++;
|
|
|
|
|
2018-02-14 00:39:06 +01:00
|
|
|
if (!job_may_gc(j))
|
2016-11-15 19:32:50 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
log_unit_debug(j->unit, "Collecting job.");
|
|
|
|
(void) job_finish_and_invalidate(j, JOB_COLLECTED, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2018-08-09 16:26:27 +02:00
|
|
|
static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) {
|
|
|
|
unsigned n = 0;
|
|
|
|
Unit *u;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
while ((u = m->stop_when_unneeded_queue)) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
assert(m->stop_when_unneeded_queue);
|
|
|
|
|
|
|
|
assert(u->in_stop_when_unneeded_queue);
|
|
|
|
LIST_REMOVE(stop_when_unneeded_queue, m->stop_when_unneeded_queue, u);
|
|
|
|
u->in_stop_when_unneeded_queue = false;
|
|
|
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (!unit_is_unneeded(u))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
log_unit_debug(u, "Unit is not needed anymore.");
|
|
|
|
|
|
|
|
/* If stopping a unit fails continuously we might enter a stop loop here, hence stop acting on the
|
|
|
|
* service being unnecessary after a while. */
|
|
|
|
|
|
|
|
if (!ratelimit_below(&u->auto_stop_ratelimit)) {
|
|
|
|
log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
|
2019-03-22 20:57:30 +01:00
|
|
|
r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
|
2018-08-09 16:26:27 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2010-04-21 03:27:44 +02:00
|
|
|
static void manager_clear_jobs_and_units(Manager *m) {
|
|
|
|
Unit *u;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
while ((u = hashmap_first(m->units)))
|
|
|
|
unit_free(u);
|
2010-06-05 02:16:20 +02:00
|
|
|
|
|
|
|
manager_dispatch_cleanup_queue(m);
|
|
|
|
|
|
|
|
assert(!m->load_queue);
|
2019-05-22 12:12:17 +02:00
|
|
|
assert(prioq_isempty(m->run_queue));
|
2010-06-05 02:16:20 +02:00
|
|
|
assert(!m->dbus_unit_queue);
|
|
|
|
assert(!m->dbus_job_queue);
|
|
|
|
assert(!m->cleanup_queue);
|
2016-11-15 19:32:50 +01:00
|
|
|
assert(!m->gc_unit_queue);
|
|
|
|
assert(!m->gc_job_queue);
|
2018-08-09 16:26:27 +02:00
|
|
|
assert(!m->stop_when_unneeded_queue);
|
2010-06-05 02:16:20 +02:00
|
|
|
|
|
|
|
assert(hashmap_isempty(m->jobs));
|
|
|
|
assert(hashmap_isempty(m->units));
|
2013-03-01 14:47:46 +01:00
|
|
|
|
|
|
|
m->n_on_console = 0;
|
|
|
|
m->n_running_jobs = 0;
|
2018-06-22 16:19:52 +02:00
|
|
|
m->n_installed_jobs = 0;
|
|
|
|
m->n_failed_jobs = 0;
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
2014-11-08 16:06:12 +01:00
|
|
|
Manager* manager_free(Manager *m) {
|
|
|
|
if (!m)
|
|
|
|
return NULL;
|
2010-04-21 03:27:44 +02:00
|
|
|
|
|
|
|
manager_clear_jobs_and_units(m);
|
2010-04-06 02:43:58 +02:00
|
|
|
|
2020-05-26 19:28:53 +02:00
|
|
|
for (UnitType c = 0; c < _UNIT_TYPE_MAX; c++)
|
2010-01-28 06:45:44 +01:00
|
|
|
if (unit_vtable[c]->shutdown)
|
|
|
|
unit_vtable[c]->shutdown(m);
|
|
|
|
|
2018-10-09 15:56:27 +02:00
|
|
|
/* Keep the cgroup hierarchy in place except when we know we are going down for good */
|
|
|
|
manager_shutdown_cgroup(m, IN_SET(m->objective, MANAGER_EXIT, MANAGER_REBOOT, MANAGER_POWEROFF, MANAGER_HALT, MANAGER_KEXEC));
|
2010-03-31 16:29:55 +02:00
|
|
|
|
2016-04-06 20:47:44 +02:00
|
|
|
lookup_paths_flush_generator(&m->lookup_paths);
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2010-06-19 03:04:04 +02:00
|
|
|
bus_done(m);
|
2019-08-07 14:58:59 +02:00
|
|
|
manager_varlink_done(m);
|
2010-02-01 03:33:24 +01:00
|
|
|
|
2018-02-06 08:00:34 +01:00
|
|
|
exec_runtime_vacuum(m);
|
|
|
|
hashmap_free(m->exec_runtime_by_id);
|
|
|
|
|
2016-07-14 12:37:28 +02:00
|
|
|
dynamic_user_vacuum(m, false);
|
|
|
|
hashmap_free(m->dynamic_users);
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
hashmap_free(m->units);
|
2016-08-30 23:18:46 +02:00
|
|
|
hashmap_free(m->units_by_invocation_id);
|
2009-11-18 00:42:52 +01:00
|
|
|
hashmap_free(m->jobs);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
hashmap_free(m->watch_pids);
|
2010-04-15 23:16:16 +02:00
|
|
|
hashmap_free(m->watch_bus);
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2019-05-22 12:12:17 +02:00
|
|
|
prioq_free(m->run_queue);
|
|
|
|
|
2014-05-15 17:09:34 +02:00
|
|
|
set_free(m->startup_units);
|
2014-03-12 20:55:13 +01:00
|
|
|
set_free(m->failed_units);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_event_source_unref(m->signal_event_source);
|
2018-01-23 18:18:13 +01:00
|
|
|
sd_event_source_unref(m->sigchld_event_source);
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_event_source_unref(m->notify_event_source);
|
2016-05-04 20:43:23 +02:00
|
|
|
sd_event_source_unref(m->cgroups_agent_event_source);
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_event_source_unref(m->time_change_event_source);
|
2018-05-28 21:33:10 +02:00
|
|
|
sd_event_source_unref(m->timezone_change_event_source);
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_event_source_unref(m->jobs_in_progress_event_source);
|
2013-11-25 15:22:41 +01:00
|
|
|
sd_event_source_unref(m->run_queue_event_source);
|
2016-08-01 19:24:40 +02:00
|
|
|
sd_event_source_unref(m->user_lookup_event_source);
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(m->signal_fd);
|
|
|
|
safe_close(m->notify_fd);
|
2016-05-04 20:43:23 +02:00
|
|
|
safe_close(m->cgroups_agent_fd);
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(m->time_change_fd);
|
2016-08-01 19:24:40 +02:00
|
|
|
safe_close_pair(m->user_lookup_fds);
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2014-10-26 02:30:51 +02:00
|
|
|
manager_close_ask_password(m);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
manager_close_idle_pipe(m);
|
|
|
|
|
|
|
|
sd_event_unref(m->event);
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2010-06-18 23:12:48 +02:00
|
|
|
free(m->notify_socket);
|
|
|
|
|
2010-06-15 14:45:15 +02:00
|
|
|
lookup_paths_free(&m->lookup_paths);
|
2018-10-31 15:49:19 +01:00
|
|
|
strv_free(m->transient_environment);
|
|
|
|
strv_free(m->client_environment);
|
2010-02-13 01:07:02 +01:00
|
|
|
|
2013-06-27 04:14:27 +02:00
|
|
|
hashmap_free(m->cgroup_unit);
|
2019-07-18 13:11:28 +02:00
|
|
|
manager_free_unit_name_maps(m);
|
2010-06-18 20:15:34 +02:00
|
|
|
|
2012-05-09 01:24:50 +02:00
|
|
|
free(m->switch_root);
|
|
|
|
free(m->switch_root_init);
|
|
|
|
|
2018-05-03 19:05:59 +02:00
|
|
|
rlimit_free_all(m->rlimit);
|
2012-03-21 18:03:40 +01:00
|
|
|
|
2013-09-26 20:14:24 +02:00
|
|
|
assert(hashmap_isempty(m->units_requiring_mounts_for));
|
|
|
|
hashmap_free(m->units_requiring_mounts_for);
|
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
hashmap_free(m->uid_refs);
|
|
|
|
hashmap_free(m->gid_refs);
|
|
|
|
|
2020-05-26 19:28:53 +02:00
|
|
|
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++)
|
2017-07-18 16:30:52 +02:00
|
|
|
m->prefix[dt] = mfree(m->prefix[dt]);
|
2020-07-23 08:49:52 +02:00
|
|
|
free(m->received_credentials);
|
2017-07-18 16:30:52 +02:00
|
|
|
|
2016-10-17 00:28:30 +02:00
|
|
|
return mfree(m);
|
2009-11-18 00:42:52 +01:00
|
|
|
}
|
|
|
|
|
core: enumerate perpetual units in a separate per-unit-type method
Previously the enumerate() callback defined for each unit type would do
two things:
1. It would create perpetual units (i.e. -.slice, system.slice, -.mount and
init.scope)
2. It would enumerate units from /proc/self/mountinfo, /proc/swaps and
the udev database
With this change these two parts are split into two seperate methods:
enumerate() now only does #2, while enumerate_perpetual() is responsible
for #1. Why make this change? Well, perpetual units should have a
slightly different effect that those found through enumeration: as
perpetual units should be up unconditionally, perpetually and thus never
change state, they should also not pull in deps by their state changing,
not even when the state is first set to active. Thus, their state is
generally initialized through the per-device coldplug() method in
similar fashion to the deserialized state from a previous run would be
put into place. OTOH units found through regular enumeration should
result in state changes (and thus pull in deps due to state changes),
hence their state should be put in effect in the catchup() method
instead. Hence, given this difference, let's also separate the
functions, so that the rule is:
1. What is created in enumerate_perpetual() should be started in
coldplug()
2. What is created in enumerate() should be started in catchup().
2018-06-05 18:26:45 +02:00
|
|
|
static void manager_enumerate_perpetual(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
2019-06-26 14:56:59 +02:00
|
|
|
if (m->test_run_flags == MANAGER_TEST_RUN_MINIMAL)
|
|
|
|
return;
|
|
|
|
|
core: enumerate perpetual units in a separate per-unit-type method
Previously the enumerate() callback defined for each unit type would do
two things:
1. It would create perpetual units (i.e. -.slice, system.slice, -.mount and
init.scope)
2. It would enumerate units from /proc/self/mountinfo, /proc/swaps and
the udev database
With this change these two parts are split into two seperate methods:
enumerate() now only does #2, while enumerate_perpetual() is responsible
for #1. Why make this change? Well, perpetual units should have a
slightly different effect that those found through enumeration: as
perpetual units should be up unconditionally, perpetually and thus never
change state, they should also not pull in deps by their state changing,
not even when the state is first set to active. Thus, their state is
generally initialized through the per-device coldplug() method in
similar fashion to the deserialized state from a previous run would be
put into place. OTOH units found through regular enumeration should
result in state changes (and thus pull in deps due to state changes),
hence their state should be put in effect in the catchup() method
instead. Hence, given this difference, let's also separate the
functions, so that the rule is:
1. What is created in enumerate_perpetual() should be started in
coldplug()
2. What is created in enumerate() should be started in catchup().
2018-06-05 18:26:45 +02:00
|
|
|
/* Let's ask every type to load all units from disk/kernel that it might know */
|
2020-05-26 19:28:53 +02:00
|
|
|
for (UnitType c = 0; c < _UNIT_TYPE_MAX; c++) {
|
core: enumerate perpetual units in a separate per-unit-type method
Previously the enumerate() callback defined for each unit type would do
two things:
1. It would create perpetual units (i.e. -.slice, system.slice, -.mount and
init.scope)
2. It would enumerate units from /proc/self/mountinfo, /proc/swaps and
the udev database
With this change these two parts are split into two seperate methods:
enumerate() now only does #2, while enumerate_perpetual() is responsible
for #1. Why make this change? Well, perpetual units should have a
slightly different effect that those found through enumeration: as
perpetual units should be up unconditionally, perpetually and thus never
change state, they should also not pull in deps by their state changing,
not even when the state is first set to active. Thus, their state is
generally initialized through the per-device coldplug() method in
similar fashion to the deserialized state from a previous run would be
put into place. OTOH units found through regular enumeration should
result in state changes (and thus pull in deps due to state changes),
hence their state should be put in effect in the catchup() method
instead. Hence, given this difference, let's also separate the
functions, so that the rule is:
1. What is created in enumerate_perpetual() should be started in
coldplug()
2. What is created in enumerate() should be started in catchup().
2018-06-05 18:26:45 +02:00
|
|
|
if (!unit_type_supported(c)) {
|
|
|
|
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unit_vtable[c]->enumerate_perpetual)
|
|
|
|
unit_vtable[c]->enumerate_perpetual(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 12:12:11 +02:00
|
|
|
static void manager_enumerate(Manager *m) {
|
2010-01-29 03:18:09 +01:00
|
|
|
assert(m);
|
|
|
|
|
2019-06-26 14:56:59 +02:00
|
|
|
if (m->test_run_flags == MANAGER_TEST_RUN_MINIMAL)
|
|
|
|
return;
|
|
|
|
|
core: enumerate perpetual units in a separate per-unit-type method
Previously the enumerate() callback defined for each unit type would do
two things:
1. It would create perpetual units (i.e. -.slice, system.slice, -.mount and
init.scope)
2. It would enumerate units from /proc/self/mountinfo, /proc/swaps and
the udev database
With this change these two parts are split into two seperate methods:
enumerate() now only does #2, while enumerate_perpetual() is responsible
for #1. Why make this change? Well, perpetual units should have a
slightly different effect that those found through enumeration: as
perpetual units should be up unconditionally, perpetually and thus never
change state, they should also not pull in deps by their state changing,
not even when the state is first set to active. Thus, their state is
generally initialized through the per-device coldplug() method in
similar fashion to the deserialized state from a previous run would be
put into place. OTOH units found through regular enumeration should
result in state changes (and thus pull in deps due to state changes),
hence their state should be put in effect in the catchup() method
instead. Hence, given this difference, let's also separate the
functions, so that the rule is:
1. What is created in enumerate_perpetual() should be started in
coldplug()
2. What is created in enumerate() should be started in catchup().
2018-06-05 18:26:45 +02:00
|
|
|
/* Let's ask every type to load all units from disk/kernel that it might know */
|
2020-05-26 19:28:53 +02:00
|
|
|
for (UnitType c = 0; c < _UNIT_TYPE_MAX; c++) {
|
2015-04-30 01:29:00 +02:00
|
|
|
if (!unit_type_supported(c)) {
|
2015-02-20 10:53:28 +01:00
|
|
|
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
|
2014-12-12 21:05:32 +01:00
|
|
|
continue;
|
2013-09-26 20:14:24 +02:00
|
|
|
}
|
2010-01-29 03:18:09 +01:00
|
|
|
|
2018-04-20 12:10:32 +02:00
|
|
|
if (unit_vtable[c]->enumerate)
|
|
|
|
unit_vtable[c]->enumerate(m);
|
2014-12-12 21:05:32 +01:00
|
|
|
}
|
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
manager_dispatch_load_queue(m);
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
2015-04-24 16:09:15 +02:00
|
|
|
static void manager_coldplug(Manager *m) {
|
2010-04-21 03:27:44 +02:00
|
|
|
Unit *u;
|
|
|
|
char *k;
|
2015-04-24 16:09:15 +02:00
|
|
|
int r;
|
2010-04-21 03:27:44 +02:00
|
|
|
|
|
|
|
assert(m);
|
2010-01-29 03:18:09 +01:00
|
|
|
|
2018-06-05 16:53:22 +02:00
|
|
|
log_debug("Invoking unit coldplug() handlers…");
|
|
|
|
|
|
|
|
/* Let's place the units back into their deserialized state */
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(u, k, m->units) {
|
2010-01-29 03:18:09 +01:00
|
|
|
|
|
|
|
/* ignore aliases */
|
2012-01-15 12:04:08 +01:00
|
|
|
if (u->id != k)
|
2010-01-29 03:18:09 +01:00
|
|
|
continue;
|
|
|
|
|
2015-04-24 16:09:15 +02:00
|
|
|
r = unit_coldplug(u);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "We couldn't coldplug %s, proceeding anyway: %m", u->id);
|
2010-01-29 03:18:09 +01:00
|
|
|
}
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
2018-06-05 16:53:22 +02:00
|
|
|
static void manager_catchup(Manager *m) {
|
|
|
|
Unit *u;
|
|
|
|
char *k;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
log_debug("Invoking unit catchup() handlers…");
|
|
|
|
|
|
|
|
/* Let's catch up on any state changes that happened while we were reloading/reexecing */
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(u, k, m->units) {
|
2018-06-05 16:53:22 +02:00
|
|
|
|
|
|
|
/* ignore aliases */
|
|
|
|
if (u->id != k)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unit_catchup(u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-10 20:42:58 +01:00
|
|
|
static void manager_distribute_fds(Manager *m, FDSet *fds) {
|
|
|
|
Unit *u;
|
2013-11-08 18:11:09 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(u, m->units) {
|
2013-11-08 18:11:09 +01:00
|
|
|
|
|
|
|
if (fdset_size(fds) <= 0)
|
|
|
|
break;
|
|
|
|
|
2015-11-10 20:42:58 +01:00
|
|
|
if (!UNIT_VTABLE(u)->distribute_fds)
|
|
|
|
continue;
|
2013-11-08 18:11:09 +01:00
|
|
|
|
2015-11-10 20:42:58 +01:00
|
|
|
UNIT_VTABLE(u)->distribute_fds(u, fds);
|
|
|
|
}
|
2013-11-08 18:11:09 +01:00
|
|
|
}
|
|
|
|
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
static bool manager_dbus_is_running(Manager *m, bool deserialized) {
|
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* This checks whether the dbus instance we are supposed to expose our APIs on is up. We check both the socket
|
|
|
|
* and the service unit. If the 'deserialized' parameter is true we'll check the deserialized state of the unit
|
|
|
|
* rather than the current one. */
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
u = manager_get_unit(m, SPECIAL_DBUS_SOCKET);
|
|
|
|
if (!u)
|
|
|
|
return false;
|
|
|
|
if ((deserialized ? SOCKET(u)->deserialized_state : SOCKET(u)->state) != SOCKET_RUNNING)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
|
|
|
|
if (!u)
|
|
|
|
return false;
|
|
|
|
if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state), SERVICE_RUNNING, SERVICE_RELOAD))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-04 20:02:59 +02:00
|
|
|
static void manager_setup_bus(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Let's set up our private bus connection now, unconditionally */
|
|
|
|
(void) bus_init_private(m);
|
|
|
|
|
|
|
|
/* If we are in --user mode also connect to the system bus now */
|
|
|
|
if (MANAGER_IS_USER(m))
|
|
|
|
(void) bus_init_system(m);
|
|
|
|
|
|
|
|
/* Let's connect to the bus now, but only if the unit is supposed to be up */
|
|
|
|
if (manager_dbus_is_running(m, MANAGER_IS_RELOADING(m))) {
|
|
|
|
(void) bus_init_api(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
(void) bus_init_system(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-04 23:05:20 +02:00
|
|
|
static void manager_preset_all(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (m->first_boot <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
|
|
|
return;
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2018-06-04 23:05:20 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* If this is the first boot, and we are in the host system, then preset everything */
|
|
|
|
r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
|
|
|
|
"Failed to populate /etc with preset unit settings, ignoring: %m");
|
|
|
|
else
|
|
|
|
log_info("Populated /etc with preset unit settings.");
|
|
|
|
}
|
|
|
|
|
2018-10-09 19:41:24 +02:00
|
|
|
static void manager_ready(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* After having loaded everything, do the final round of catching up with what might have changed */
|
|
|
|
|
|
|
|
m->objective = MANAGER_OK; /* Tell everyone we are up now */
|
|
|
|
|
|
|
|
/* It might be safe to log to the journal now and connect to dbus */
|
|
|
|
manager_recheck_journal(m);
|
|
|
|
manager_recheck_dbus(m);
|
|
|
|
|
|
|
|
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
|
|
|
|
manager_catchup(m);
|
2019-03-15 11:37:43 +01:00
|
|
|
|
|
|
|
m->honor_device_enumeration = true;
|
2018-10-09 19:41:24 +02:00
|
|
|
}
|
|
|
|
|
2018-10-10 13:33:49 +02:00
|
|
|
static Manager* manager_reloading_start(Manager *m) {
|
|
|
|
m->n_reloading++;
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
static void manager_reloading_stopp(Manager **m) {
|
|
|
|
if (*m) {
|
|
|
|
assert((*m)->n_reloading > 0);
|
|
|
|
(*m)->n_reloading--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-21 03:27:44 +02:00
|
|
|
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
2017-11-15 10:38:04 +01:00
|
|
|
int r;
|
2010-04-21 03:27:44 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
/* If we are running in test mode, we still want to run the generators,
|
|
|
|
* but we should not touch the real generator directories. */
|
|
|
|
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope,
|
2018-10-09 16:15:54 +02:00
|
|
|
MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
|
2017-09-14 19:26:29 +02:00
|
|
|
NULL);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
if (r < 0)
|
2018-10-09 17:16:08 +02:00
|
|
|
return log_error_errno(r, "Failed to initialize path lookup table: %m");
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2018-07-22 06:41:44 +02:00
|
|
|
dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START));
|
2018-10-09 19:42:28 +02:00
|
|
|
r = manager_run_environment_generators(m);
|
|
|
|
if (r >= 0)
|
|
|
|
r = manager_run_generators(m);
|
2018-07-22 06:41:44 +02:00
|
|
|
dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_FINISH));
|
2012-05-23 03:43:29 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-06-04 23:05:20 +02:00
|
|
|
manager_preset_all(m);
|
2018-10-09 17:16:08 +02:00
|
|
|
|
core: stop removing non-existent and duplicate lookup paths
When we would iterate over the lookup paths for each unit, making the list as
short as possible was important for performance. With the current cache, it
doesn't matter much. Two classes of paths were being removed:
- paths which don't exist in the filesystem
- paths which symlink to a path earlier in the search list
Both of those points cause problems with the caching code:
- if a user creates a directory that didn't exist before and puts units there,
now we will notice the new mtime an properly load the unit. When the path
was removed from list, we wouldn't.
- we now properly detect whether a unit path is on the path or not.
Before, if e.g. /lib/systemd/system, /usr/lib/systemd/systemd were both on
the path, and /lib was a symlink to /usr/lib, the second directory would be
pruned from the path. Then, the code would think that a symlink
/etc/systemd/system/foo.service→/lib/systemd/system/foo.service is an alias,
but /etc/systemd/system/foo.service→/usr/lib/systemd/system/foo.service would
be considered a link (in the systemctl link sense).
Removing the pruning has a slight negative performance impact in case of
usr-merge systems which have systemd compiled with non-usr-merge paths.
Non-usr-merge systems are deprecated, and this impact should be very small, so
I think it's OK. If it turns out to be an issue, the loop in function that
builds the cache could be improved to skip over "duplicate" directories with
same logic that the cache pruning did before. I didn't want to add this,
becuase it complicates the code to improve a corner case.
Fixes #13272.
2019-08-26 08:58:41 +02:00
|
|
|
lookup_paths_log(&m->lookup_paths);
|
2018-10-09 17:16:08 +02:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
{
|
|
|
|
/* This block is (optionally) done with the reloading counter bumped */
|
|
|
|
_cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
|
|
|
|
|
|
|
|
/* If we will deserialize make sure that during enumeration this is already known, so we increase the
|
|
|
|
* counter here already */
|
|
|
|
if (serialization)
|
|
|
|
reloading = manager_reloading_start(m);
|
|
|
|
|
|
|
|
/* First, enumerate what we can from all config files */
|
|
|
|
dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_UNITS_LOAD_START));
|
|
|
|
manager_enumerate_perpetual(m);
|
|
|
|
manager_enumerate(m);
|
|
|
|
dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_UNITS_LOAD_FINISH));
|
|
|
|
|
|
|
|
/* Second, deserialize if there is something to deserialize */
|
|
|
|
if (serialization) {
|
|
|
|
r = manager_deserialize(m, serialization, fds);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Deserialization failed: %m");
|
|
|
|
}
|
2012-12-22 19:30:07 +01:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
/* Any fds left? Find some unit which wants them. This is useful to allow container managers to pass
|
|
|
|
* some file descriptors to us pre-initialized. This enables socket-based activation of entire
|
|
|
|
* containers. */
|
|
|
|
manager_distribute_fds(m, fds);
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
/* We might have deserialized the notify fd, but if we didn't then let's create the bus now */
|
|
|
|
r = manager_setup_notify(m);
|
|
|
|
if (r < 0)
|
|
|
|
/* No sense to continue without notifications, our children would fail anyway. */
|
|
|
|
return r;
|
2016-05-04 20:43:23 +02:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
r = manager_setup_cgroups_agent(m);
|
|
|
|
if (r < 0)
|
|
|
|
/* Likewise, no sense to continue without empty cgroup notifications. */
|
|
|
|
return r;
|
2016-08-01 19:24:40 +02:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
r = manager_setup_user_lookup_fd(m);
|
|
|
|
if (r < 0)
|
|
|
|
/* This shouldn't fail, except if things are really broken. */
|
|
|
|
return r;
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
/* Connect to the bus if we are good for it */
|
|
|
|
manager_setup_bus(m);
|
2013-11-30 03:53:42 +01:00
|
|
|
|
2019-04-27 02:22:40 +02:00
|
|
|
/* Now that we are connected to all possible buses, let's deserialize who is tracking us. */
|
2018-10-10 13:41:44 +02:00
|
|
|
r = bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to deserialized tracked clients, ignoring: %m");
|
|
|
|
m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2019-08-07 14:58:59 +02:00
|
|
|
r = manager_varlink_init(m);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to set up Varlink server, ignoring: %m");
|
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
/* Third, fire things up! */
|
|
|
|
manager_coldplug(m);
|
2018-10-09 17:37:57 +02:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
/* Clean up runtime objects */
|
|
|
|
manager_vacuum(m);
|
2013-07-10 21:10:53 +02:00
|
|
|
|
2018-10-10 13:41:44 +02:00
|
|
|
if (serialization)
|
|
|
|
/* Let's wait for the UnitNew/JobNew messages being sent, before we notify that the
|
|
|
|
* reload is finished */
|
|
|
|
m->send_reloading_done = true;
|
2010-07-13 19:01:20 +02:00
|
|
|
}
|
|
|
|
|
2018-10-09 19:41:24 +02:00
|
|
|
manager_ready(m);
|
2018-06-05 16:53:22 +02:00
|
|
|
|
2017-11-15 10:38:04 +01:00
|
|
|
return 0;
|
2010-01-29 03:18:09 +01:00
|
|
|
}
|
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
int manager_add_job(
|
|
|
|
Manager *m,
|
|
|
|
JobType type,
|
|
|
|
Unit *unit,
|
|
|
|
JobMode mode,
|
|
|
|
Set *affected_jobs,
|
|
|
|
sd_bus_error *error,
|
|
|
|
Job **ret) {
|
|
|
|
|
2012-04-20 10:22:07 +02:00
|
|
|
Transaction *tr;
|
2019-03-22 20:57:30 +01:00
|
|
|
int r;
|
2010-01-20 02:12:51 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(type < _JOB_TYPE_MAX);
|
2010-01-26 21:39:06 +01:00
|
|
|
assert(unit);
|
2010-01-20 02:12:51 +01:00
|
|
|
assert(mode < _JOB_MODE_MAX);
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2014-10-31 01:32:17 +01:00
|
|
|
if (mode == JOB_ISOLATE && type != JOB_START)
|
2019-03-22 20:57:30 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
|
2010-04-22 02:42:59 +02:00
|
|
|
|
2014-10-31 01:32:17 +01:00
|
|
|
if (mode == JOB_ISOLATE && !unit->allow_isolate)
|
2019-03-22 20:57:30 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
|
2010-08-30 22:45:46 +02:00
|
|
|
|
2019-11-01 08:54:03 +01:00
|
|
|
if (mode == JOB_TRIGGERING && type != JOB_STOP)
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=triggering is only valid for stop.");
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
|
2010-01-29 04:11:36 +01:00
|
|
|
|
2015-05-19 18:13:22 +02:00
|
|
|
type = job_type_collapse(type, unit);
|
core: add NOP jobs, job type collapsing
Two of our current job types are special:
JOB_TRY_RESTART, JOB_RELOAD_OR_START.
They differ from other job types by being sensitive to the unit active state.
They perform some action when the unit is active and some other action
otherwise. This raises a question: when exactly should the unit state be
checked to make the decision?
Currently the unit state is checked when the job becomes runnable. It's more
sensible to check the state immediately when the job is added by the user.
When the user types "systemctl try-restart foo.service", he really intends
to restart the service if it's running right now. If it isn't running right
now, the restart is pointless.
Consider the example (from Bugzilla[1]):
sleep.service takes some time to start.
hello.service has After=sleep.service.
Both services get started. Two jobs will appear:
hello.service/start waiting
sleep.service/start running
Then someone runs "systemctl try-restart hello.service".
Currently the try-restart operation will block and wait for
sleep.service/start to complete.
The correct result is to complete the try-restart operation immediately
with success, because hello.service is not running. The two original
jobs must not be disturbed by this.
To fix this we introduce two new concepts:
- a new job type: JOB_NOP
A JOB_NOP job does not do anything to the unit. It does not pull in any
dependencies. It is always immediately runnable. When installed to a unit,
it sits in a special slot (u->nop_job) where it never conflicts with
the installed job (u->job) of a different type. It never merges with jobs
of other types, but it can merge into an already installed JOB_NOP job.
- "collapsing" of job types
When a job of one of the two special types is added, the state of the unit
is checked immediately and the job type changes:
JOB_TRY_RESTART -> JOB_RESTART or JOB_NOP
JOB_RELOAD_OR_START -> JOB_RELOAD or JOB_START
Should a job type JOB_RELOAD_OR_START appear later during job merging, it
collapses immediately afterwards.
Collapsing actually makes some things simpler, because there are now fewer
job types that are allowed in the transaction.
[1] Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=753586
2012-04-25 11:58:27 +02:00
|
|
|
|
2013-02-22 11:21:37 +01:00
|
|
|
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
|
2012-04-20 10:22:07 +02:00
|
|
|
if (!tr)
|
|
|
|
return -ENOMEM;
|
2010-01-19 04:15:20 +01:00
|
|
|
|
2015-11-12 19:52:31 +01:00
|
|
|
r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
|
2017-09-29 00:37:23 +02:00
|
|
|
IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
|
2019-03-22 20:57:30 +01:00
|
|
|
mode == JOB_IGNORE_DEPENDENCIES, error);
|
2012-04-20 10:22:07 +02:00
|
|
|
if (r < 0)
|
|
|
|
goto tr_abort;
|
2010-04-22 02:42:59 +02:00
|
|
|
|
2012-04-20 10:22:07 +02:00
|
|
|
if (mode == JOB_ISOLATE) {
|
|
|
|
r = transaction_add_isolate_jobs(tr, m);
|
|
|
|
if (r < 0)
|
|
|
|
goto tr_abort;
|
|
|
|
}
|
|
|
|
|
2019-11-01 08:54:03 +01:00
|
|
|
if (mode == JOB_TRIGGERING) {
|
|
|
|
r = transaction_add_triggering_jobs(tr, unit);
|
|
|
|
if (r < 0)
|
|
|
|
goto tr_abort;
|
|
|
|
}
|
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
r = transaction_activate(tr, m, mode, affected_jobs, error);
|
2012-04-20 10:22:07 +02:00
|
|
|
if (r < 0)
|
|
|
|
goto tr_abort;
|
2010-01-20 02:12:51 +01:00
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(unit,
|
2013-01-05 18:00:35 +01:00
|
|
|
"Enqueued job %s/%s as %u", unit->id,
|
|
|
|
job_type_to_string(type), (unsigned) tr->anchor_job->id);
|
2010-01-29 03:18:09 +01:00
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
if (ret)
|
|
|
|
*ret = tr->anchor_job;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2012-04-20 10:22:07 +02:00
|
|
|
transaction_free(tr);
|
2010-01-20 02:12:51 +01:00
|
|
|
return 0;
|
2012-04-20 10:22:07 +02:00
|
|
|
|
|
|
|
tr_abort:
|
|
|
|
transaction_abort(tr);
|
|
|
|
transaction_free(tr);
|
|
|
|
return r;
|
2010-01-20 02:12:51 +01:00
|
|
|
}
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **ret) {
|
2017-02-12 18:56:40 +01:00
|
|
|
Unit *unit = NULL; /* just to appease gcc, initialization is not really necessary */
|
2010-04-13 01:59:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(type < _JOB_TYPE_MAX);
|
|
|
|
assert(name);
|
|
|
|
assert(mode < _JOB_MODE_MAX);
|
|
|
|
|
2012-09-18 01:55:49 +02:00
|
|
|
r = manager_load_unit(m, name, NULL, NULL, &unit);
|
|
|
|
if (r < 0)
|
2010-04-13 01:59:06 +02:00
|
|
|
return r;
|
2017-02-12 18:56:40 +01:00
|
|
|
assert(unit);
|
2010-04-13 01:59:06 +02:00
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
return manager_add_job(m, type, unit, mode, affected_jobs, e, ret);
|
2015-11-12 20:13:42 +01:00
|
|
|
}
|
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-11-12 20:13:42 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(type < _JOB_TYPE_MAX);
|
|
|
|
assert(name);
|
|
|
|
assert(mode < _JOB_MODE_MAX);
|
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
r = manager_add_job_by_name(m, type, name, mode, affected_jobs, &error, ret);
|
2015-11-12 20:13:42 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
|
|
|
|
|
|
|
|
return r;
|
2010-04-13 01:59:06 +02:00
|
|
|
}
|
|
|
|
|
2017-08-07 11:27:24 +02:00
|
|
|
int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e) {
|
|
|
|
int r;
|
|
|
|
Transaction *tr;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(unit);
|
|
|
|
assert(mode < _JOB_MODE_MAX);
|
|
|
|
assert(mode != JOB_ISOLATE); /* Isolate is only valid for start */
|
|
|
|
|
|
|
|
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
|
|
|
|
if (!tr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* We need an anchor job */
|
|
|
|
r = transaction_add_job_and_dependencies(tr, JOB_NOP, unit, NULL, false, false, true, true, e);
|
|
|
|
if (r < 0)
|
|
|
|
goto tr_abort;
|
|
|
|
|
|
|
|
/* Failure in adding individual dependencies is ignored, so this always succeeds. */
|
|
|
|
transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
|
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
r = transaction_activate(tr, m, mode, NULL, e);
|
2017-08-07 11:27:24 +02:00
|
|
|
if (r < 0)
|
|
|
|
goto tr_abort;
|
|
|
|
|
|
|
|
transaction_free(tr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
tr_abort:
|
|
|
|
transaction_abort(tr);
|
|
|
|
transaction_free(tr);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-11-18 00:42:52 +01:00
|
|
|
Job *manager_get_job(Manager *m, uint32_t id) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
return hashmap_get(m->jobs, UINT32_TO_PTR(id));
|
|
|
|
}
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
Unit *manager_get_unit(Manager *m, const char *name) {
|
2009-11-18 00:42:52 +01:00
|
|
|
assert(m);
|
|
|
|
assert(name);
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
return hashmap_get(m->units, name);
|
2009-11-18 00:42:52 +01:00
|
|
|
}
|
|
|
|
|
2018-03-23 15:28:06 +01:00
|
|
|
static int manager_dispatch_target_deps_queue(Manager *m) {
|
|
|
|
Unit *u;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
static const UnitDependency deps[] = {
|
|
|
|
UNIT_REQUIRED_BY,
|
|
|
|
UNIT_REQUISITE_OF,
|
|
|
|
UNIT_WANTED_BY,
|
|
|
|
UNIT_BOUND_BY
|
|
|
|
};
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
while ((u = m->target_deps_queue)) {
|
|
|
|
assert(u->in_target_deps_queue);
|
|
|
|
|
|
|
|
LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
|
|
|
|
u->in_target_deps_queue = false;
|
|
|
|
|
2020-09-04 17:28:53 +02:00
|
|
|
for (size_t k = 0; k < ELEMENTSOF(deps); k++) {
|
2018-03-23 15:28:06 +01:00
|
|
|
Unit *target;
|
|
|
|
void *v;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]]) {
|
2018-03-23 15:28:06 +01:00
|
|
|
r = unit_add_default_target_dependency(u, target);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-02-05 00:38:41 +01:00
|
|
|
unsigned manager_dispatch_load_queue(Manager *m) {
|
2012-01-15 12:37:16 +01:00
|
|
|
Unit *u;
|
2010-02-05 00:38:41 +01:00
|
|
|
unsigned n = 0;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2009-11-19 02:52:17 +01:00
|
|
|
/* Make sure we are not run recursively */
|
|
|
|
if (m->dispatching_load_queue)
|
2010-02-05 00:38:41 +01:00
|
|
|
return 0;
|
2009-11-19 02:52:17 +01:00
|
|
|
|
|
|
|
m->dispatching_load_queue = true;
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
/* Dispatches the load queue. Takes a unit from the queue and
|
2009-11-18 00:42:52 +01:00
|
|
|
* tries to load its data until the queue is empty */
|
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
while ((u = m->load_queue)) {
|
|
|
|
assert(u->in_load_queue);
|
2010-01-26 04:18:44 +01:00
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
unit_load(u);
|
2010-02-05 00:38:41 +01:00
|
|
|
n++;
|
2009-11-18 00:42:52 +01:00
|
|
|
}
|
|
|
|
|
2009-11-19 02:52:17 +01:00
|
|
|
m->dispatching_load_queue = false;
|
2018-03-23 15:28:06 +01:00
|
|
|
|
|
|
|
/* Dispatch the units waiting for their target dependencies to be added now, as all targets that we know about
|
|
|
|
* should be loaded and have aliases resolved */
|
|
|
|
(void) manager_dispatch_target_deps_queue(m);
|
|
|
|
|
2010-02-05 00:38:41 +01:00
|
|
|
return n;
|
2009-11-18 00:42:52 +01:00
|
|
|
}
|
|
|
|
|
2020-08-28 10:32:39 +02:00
|
|
|
bool manager_unit_cache_should_retry_load(Unit *u) {
|
2020-07-03 19:45:19 +02:00
|
|
|
assert(u);
|
|
|
|
|
2020-08-28 10:32:39 +02:00
|
|
|
/* Automatic reloading from disk only applies to units which were not found sometime in the past, and
|
|
|
|
* the not-found stub is kept pinned in the unit graph by dependencies. For units that were
|
|
|
|
* previously loaded, we don't do automatic reloading, and daemon-reload is necessary to update. */
|
2020-07-03 19:45:19 +02:00
|
|
|
if (u->load_state != UNIT_NOT_FOUND)
|
|
|
|
return false;
|
|
|
|
|
2020-08-28 10:32:39 +02:00
|
|
|
/* The cache has been updated since the last time we tried to load the unit. There might be new
|
|
|
|
* fragment paths to read. */
|
2020-08-28 12:21:48 +02:00
|
|
|
if (u->manager->unit_cache_timestamp_hash != u->fragment_not_found_timestamp_hash)
|
2020-07-03 19:45:19 +02:00
|
|
|
return true;
|
2020-05-08 00:26:53 +02:00
|
|
|
|
2020-08-28 10:32:39 +02:00
|
|
|
/* The cache needs to be updated because there are modifications on disk. */
|
2020-08-28 12:21:48 +02:00
|
|
|
return !lookup_paths_timestamp_hash_same(&u->manager->lookup_paths, u->manager->unit_cache_timestamp_hash, NULL);
|
2020-05-08 00:26:53 +02:00
|
|
|
}
|
|
|
|
|
2013-06-28 04:12:58 +02:00
|
|
|
int manager_load_unit_prepare(
|
|
|
|
Manager *m,
|
|
|
|
const char *name,
|
|
|
|
const char *path,
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_bus_error *e,
|
2013-06-28 04:12:58 +02:00
|
|
|
Unit **_ret) {
|
|
|
|
|
2018-03-09 21:34:28 +01:00
|
|
|
_cleanup_(unit_freep) Unit *cleanup_ret = NULL;
|
2010-01-26 21:39:06 +01:00
|
|
|
Unit *ret;
|
2012-01-15 10:53:49 +01:00
|
|
|
UnitType t;
|
2009-11-18 00:42:52 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2017-02-12 18:40:09 +01:00
|
|
|
assert(_ret);
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2010-04-24 04:26:33 +02:00
|
|
|
/* This will prepare the unit for loading, but not actually
|
|
|
|
* load anything from disk. */
|
2010-01-27 00:15:56 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
if (path && !is_path(path))
|
|
|
|
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
|
2010-04-15 03:11:11 +02:00
|
|
|
|
2020-05-06 21:24:05 +02:00
|
|
|
if (!name) {
|
|
|
|
/* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
|
|
|
|
* workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
|
|
|
|
* but this cannot be possible in any code path (See #6119). */
|
|
|
|
assert_se(path);
|
2013-12-07 03:29:55 +01:00
|
|
|
name = basename(path);
|
2020-05-06 21:24:05 +02:00
|
|
|
}
|
2010-04-15 03:11:11 +02:00
|
|
|
|
2012-01-15 10:53:49 +01:00
|
|
|
t = unit_name_to_type(name);
|
|
|
|
|
2016-03-30 13:49:50 +02:00
|
|
|
if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
|
|
|
|
if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
|
|
|
|
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is missing the instance name.", name);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
|
2016-03-30 13:49:50 +02:00
|
|
|
}
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2012-01-15 10:53:49 +01:00
|
|
|
ret = manager_get_unit(m, name);
|
|
|
|
if (ret) {
|
2020-05-08 00:26:53 +02:00
|
|
|
/* The time-based cache allows to start new units without daemon-reload,
|
|
|
|
* but if they are already referenced (because of dependencies or ordering)
|
|
|
|
* then we have to force a load of the fragment. As an optimization, check
|
|
|
|
* first if anything in the usual paths was modified since the last time
|
2020-06-16 19:46:55 +02:00
|
|
|
* the cache was loaded. Also check if the last time an attempt to load the
|
|
|
|
* unit was made was before the most recent cache refresh, so that we know
|
2020-08-28 10:32:39 +02:00
|
|
|
* we need to try again — even if the cache is current, it might have been
|
2020-06-16 19:46:55 +02:00
|
|
|
* updated in a different context before we had a chance to retry loading
|
|
|
|
* this particular unit. */
|
2020-08-28 10:32:39 +02:00
|
|
|
if (manager_unit_cache_should_retry_load(ret))
|
2020-05-08 00:26:53 +02:00
|
|
|
ret->load_state = UNIT_STUB;
|
|
|
|
else {
|
|
|
|
*_ret = ret;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = cleanup_ret = unit_new(m, unit_vtable[t]->object_size);
|
|
|
|
if (!ret)
|
|
|
|
return -ENOMEM;
|
2010-01-26 04:18:44 +01:00
|
|
|
}
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2012-01-15 10:53:49 +01:00
|
|
|
if (path) {
|
2020-05-08 00:26:53 +02:00
|
|
|
r = free_and_strdup(&ret->fragment_path, path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-01-15 10:53:49 +01:00
|
|
|
}
|
2010-01-27 00:15:56 +01:00
|
|
|
|
2013-05-31 02:28:09 +02:00
|
|
|
r = unit_add_name(ret, name);
|
2018-03-09 21:34:28 +01:00
|
|
|
if (r < 0)
|
2010-01-21 00:51:37 +01:00
|
|
|
return r;
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
unit_add_to_load_queue(ret);
|
2010-02-05 00:38:41 +01:00
|
|
|
unit_add_to_dbus_queue(ret);
|
2010-05-16 04:31:07 +02:00
|
|
|
unit_add_to_gc_queue(ret);
|
2010-02-05 00:38:41 +01:00
|
|
|
|
2017-02-12 18:40:09 +01:00
|
|
|
*_ret = ret;
|
2018-03-09 21:34:28 +01:00
|
|
|
cleanup_ret = NULL;
|
2010-04-24 04:26:33 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-28 04:12:58 +02:00
|
|
|
int manager_load_unit(
|
|
|
|
Manager *m,
|
|
|
|
const char *name,
|
|
|
|
const char *path,
|
2013-11-19 21:12:59 +01:00
|
|
|
sd_bus_error *e,
|
2013-06-28 04:12:58 +02:00
|
|
|
Unit **_ret) {
|
|
|
|
|
2010-04-24 04:26:33 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2017-02-12 18:40:09 +01:00
|
|
|
assert(_ret);
|
2010-04-24 04:26:33 +02:00
|
|
|
|
|
|
|
/* This will load the service information files, but not actually
|
|
|
|
* start any services or anything. */
|
|
|
|
|
2012-09-18 01:55:49 +02:00
|
|
|
r = manager_load_unit_prepare(m, name, path, e, _ret);
|
|
|
|
if (r != 0)
|
2010-04-24 04:26:33 +02:00
|
|
|
return r;
|
|
|
|
|
2010-01-29 03:18:09 +01:00
|
|
|
manager_dispatch_load_queue(m);
|
2009-11-18 00:42:52 +01:00
|
|
|
|
2017-02-12 18:40:09 +01:00
|
|
|
*_ret = unit_follow_merge(*_ret);
|
2018-04-12 15:13:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_load_startable_unit_or_warn(
|
|
|
|
Manager *m,
|
|
|
|
const char *name,
|
|
|
|
const char *path,
|
|
|
|
Unit **ret) {
|
|
|
|
|
|
|
|
/* Load a unit, make sure it loaded fully and is not masked. */
|
|
|
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
Unit *unit;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = manager_load_unit(m, name, path, &error, &unit);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to load %s %s: %s",
|
2018-06-01 17:37:20 +02:00
|
|
|
name ? "unit" : "unit file", name ?: path,
|
2018-04-12 15:13:14 +02:00
|
|
|
bus_error_message(&error, r));
|
2018-06-01 17:37:20 +02:00
|
|
|
|
|
|
|
r = bus_unit_validate_load_state(unit, &error);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "%s", bus_error_message(&error, r));
|
2010-04-15 03:11:11 +02:00
|
|
|
|
2018-04-12 15:13:14 +02:00
|
|
|
*ret = unit;
|
2009-11-18 00:42:52 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2010-01-19 00:22:34 +01:00
|
|
|
|
2010-01-20 04:02:39 +01:00
|
|
|
void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
|
2010-01-19 00:22:34 +01:00
|
|
|
Job *j;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(f);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(j, s->jobs)
|
2010-01-20 04:02:39 +01:00
|
|
|
job_dump(j, f, prefix);
|
2010-01-19 00:22:34 +01:00
|
|
|
}
|
|
|
|
|
2010-01-26 21:39:06 +01:00
|
|
|
void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
|
|
|
|
Unit *u;
|
2010-01-19 04:15:20 +01:00
|
|
|
const char *t;
|
2010-01-19 00:22:34 +01:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(f);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(u, t, s->units)
|
2012-01-15 12:04:08 +01:00
|
|
|
if (u->id == t)
|
2010-01-26 21:39:06 +01:00
|
|
|
unit_dump(u, f, prefix);
|
2010-01-19 00:22:34 +01:00
|
|
|
}
|
2010-01-20 05:03:52 +01:00
|
|
|
|
2017-11-20 21:11:32 +01:00
|
|
|
void manager_dump(Manager *m, FILE *f, const char *prefix) {
|
|
|
|
assert(m);
|
|
|
|
assert(f);
|
|
|
|
|
2020-09-04 17:28:53 +02:00
|
|
|
for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
|
2019-07-04 19:12:03 +02:00
|
|
|
const dual_timestamp *t = m->timestamps + q;
|
|
|
|
char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)];
|
2017-11-20 21:11:32 +01:00
|
|
|
|
2019-07-04 19:12:03 +02:00
|
|
|
if (dual_timestamp_is_set(t))
|
2017-11-20 21:11:32 +01:00
|
|
|
fprintf(f, "%sTimestamp %s: %s\n",
|
|
|
|
strempty(prefix),
|
|
|
|
manager_timestamp_to_string(q),
|
2019-07-04 19:12:03 +02:00
|
|
|
timestamp_is_set(t->realtime) ? format_timestamp(buf, sizeof buf, t->realtime) :
|
|
|
|
format_timespan(buf, sizeof buf, t->monotonic, 1));
|
2017-11-20 21:11:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
manager_dump_units(m, f, prefix);
|
|
|
|
manager_dump_jobs(m, f, prefix);
|
|
|
|
}
|
|
|
|
|
2017-11-20 21:20:44 +01:00
|
|
|
int manager_get_dump_string(Manager *m, char **ret) {
|
|
|
|
_cleanup_free_ char *dump = NULL;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
size_t size;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(ret);
|
|
|
|
|
2019-04-04 11:46:44 +02:00
|
|
|
f = open_memstream_unlocked(&dump, &size);
|
2017-11-20 21:20:44 +01:00
|
|
|
if (!f)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
manager_dump(m, f, NULL);
|
|
|
|
|
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
f = safe_fclose(f);
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(dump);
|
2017-11-20 21:20:44 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-20 05:03:52 +01:00
|
|
|
void manager_clear_jobs(Manager *m) {
|
|
|
|
Job *j;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
while ((j = hashmap_first(m->jobs)))
|
2012-04-24 11:21:03 +02:00
|
|
|
/* No need to recurse. We're cancelling all jobs. */
|
2016-05-16 17:24:51 +02:00
|
|
|
job_finish_and_invalidate(j, JOB_CANCELED, false, false);
|
2010-01-20 05:03:52 +01:00
|
|
|
}
|
2010-01-23 22:56:47 +01:00
|
|
|
|
2019-03-18 20:59:36 +01:00
|
|
|
void manager_unwatch_pid(Manager *m, pid_t pid) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* First let's drop the unit keyed as "pid". */
|
|
|
|
(void) hashmap_remove(m->watch_pids, PID_TO_PTR(pid));
|
|
|
|
|
|
|
|
/* Then, let's also drop the array keyed by -pid. */
|
|
|
|
free(hashmap_remove(m->watch_pids, PID_TO_PTR(-pid)));
|
|
|
|
}
|
|
|
|
|
2013-11-25 15:22:41 +01:00
|
|
|
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
2010-01-23 22:56:47 +01:00
|
|
|
Job *j;
|
2010-01-26 04:18:44 +01:00
|
|
|
|
2013-11-25 15:22:41 +01:00
|
|
|
assert(source);
|
|
|
|
assert(m);
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2019-05-22 12:12:17 +02:00
|
|
|
while ((j = prioq_peek(m->run_queue))) {
|
2010-01-26 19:25:02 +01:00
|
|
|
assert(j->installed);
|
2010-01-26 04:18:44 +01:00
|
|
|
assert(j->in_run_queue);
|
|
|
|
|
2018-11-14 11:38:51 +01:00
|
|
|
(void) job_run_and_invalidate(j);
|
2010-01-24 00:39:29 +01:00
|
|
|
}
|
2010-01-26 04:18:44 +01:00
|
|
|
|
2013-03-04 14:38:51 +01:00
|
|
|
if (m->n_running_jobs > 0)
|
2013-02-28 00:03:22 +01:00
|
|
|
manager_watch_jobs_in_progress(m);
|
|
|
|
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
if (m->n_on_console > 0)
|
|
|
|
manager_watch_idle_pipe(m);
|
|
|
|
|
2013-11-25 15:22:41 +01:00
|
|
|
return 1;
|
2010-02-05 00:38:41 +01:00
|
|
|
}
|
|
|
|
|
2013-11-08 18:11:09 +01:00
|
|
|
static unsigned manager_dispatch_dbus_queue(Manager *m) {
|
2018-02-13 18:30:34 +01:00
|
|
|
unsigned n = 0, budget;
|
2012-01-15 12:37:16 +01:00
|
|
|
Unit *u;
|
2018-02-13 18:30:34 +01:00
|
|
|
Job *j;
|
2010-02-05 00:38:41 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2018-11-13 12:48:49 +01:00
|
|
|
/* When we are reloading, let's not wait with generating signals, since we need to exit the manager as quickly
|
|
|
|
* as we can. There's no point in throttling generation of signals in that case. */
|
|
|
|
if (MANAGER_IS_RELOADING(m) || m->send_reloading_done || m->pending_reload_message)
|
|
|
|
budget = (unsigned) -1; /* infinite budget in this case */
|
|
|
|
else {
|
|
|
|
/* Anything to do at all? */
|
|
|
|
if (!m->dbus_unit_queue && !m->dbus_job_queue)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Do we have overly many messages queued at the moment? If so, let's not enqueue more on top, let's
|
|
|
|
* sit this cycle out, and process things in a later cycle when the queues got a bit emptier. */
|
|
|
|
if (manager_bus_n_queued_write(m) > MANAGER_BUS_BUSY_THRESHOLD)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Only process a certain number of units/jobs per event loop iteration. Even if the bus queue wasn't
|
|
|
|
* overly full before this call we shouldn't increase it in size too wildly in one step, and we
|
|
|
|
* shouldn't monopolize CPU time with generating these messages. Note the difference in counting of
|
|
|
|
* this "budget" and the "threshold" above: the "budget" is decreased only once per generated message,
|
2019-04-27 02:22:40 +02:00
|
|
|
* regardless how many buses/direct connections it is enqueued on, while the "threshold" is applied to
|
|
|
|
* each queued instance of bus message, i.e. if the same message is enqueued to five buses/direct
|
2018-11-13 12:48:49 +01:00
|
|
|
* connections it will be counted five times. This difference in counting ("references"
|
|
|
|
* vs. "instances") is primarily a result of the fact that it's easier to implement it this way,
|
|
|
|
* however it also reflects the thinking that the "threshold" should put a limit on used queue memory,
|
|
|
|
* i.e. space, while the "budget" should put a limit on time. Also note that the "threshold" is
|
|
|
|
* currently chosen much higher than the "budget". */
|
|
|
|
budget = MANAGER_BUS_MESSAGE_BUDGET;
|
|
|
|
}
|
2018-02-13 18:30:34 +01:00
|
|
|
|
2018-11-13 12:48:49 +01:00
|
|
|
while (budget != 0 && (u = m->dbus_unit_queue)) {
|
2018-02-13 18:30:34 +01:00
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
assert(u->in_dbus_queue);
|
2010-02-05 00:38:41 +01:00
|
|
|
|
2012-01-15 12:37:16 +01:00
|
|
|
bus_unit_send_change_signal(u);
|
2018-11-13 12:48:49 +01:00
|
|
|
n++;
|
|
|
|
|
|
|
|
if (budget != (unsigned) -1)
|
|
|
|
budget--;
|
2010-02-05 00:38:41 +01:00
|
|
|
}
|
|
|
|
|
2018-11-13 12:48:49 +01:00
|
|
|
while (budget != 0 && (j = m->dbus_job_queue)) {
|
2010-02-05 00:38:41 +01:00
|
|
|
assert(j->in_dbus_queue);
|
|
|
|
|
|
|
|
bus_job_send_change_signal(j);
|
2018-11-13 12:48:49 +01:00
|
|
|
n++;
|
|
|
|
|
|
|
|
if (budget != (unsigned) -1)
|
|
|
|
budget--;
|
2010-02-05 00:38:41 +01:00
|
|
|
}
|
|
|
|
|
2018-11-13 12:48:49 +01:00
|
|
|
if (m->send_reloading_done) {
|
2013-07-10 21:10:53 +02:00
|
|
|
m->send_reloading_done = false;
|
2013-11-19 21:12:59 +01:00
|
|
|
bus_manager_send_reloading(m, false);
|
2018-11-13 12:48:49 +01:00
|
|
|
n++;
|
2013-07-10 21:10:53 +02:00
|
|
|
}
|
|
|
|
|
2018-11-13 12:48:49 +01:00
|
|
|
if (m->pending_reload_message) {
|
2018-11-13 11:59:06 +01:00
|
|
|
bus_send_pending_reload_message(m);
|
2018-02-13 18:30:34 +01:00
|
|
|
n++;
|
|
|
|
}
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2010-02-05 00:38:41 +01:00
|
|
|
return n;
|
2010-01-24 00:39:29 +01:00
|
|
|
}
|
|
|
|
|
2016-05-04 20:43:23 +02:00
|
|
|
static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
2018-12-07 16:22:10 +01:00
|
|
|
char buf[PATH_MAX];
|
2016-05-04 20:43:23 +02:00
|
|
|
ssize_t n;
|
|
|
|
|
|
|
|
n = recv(fd, buf, sizeof(buf), 0);
|
|
|
|
if (n < 0)
|
|
|
|
return log_error_errno(errno, "Failed to read cgroups agent message: %m");
|
|
|
|
if (n == 0) {
|
|
|
|
log_error("Got zero-length cgroups agent message, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ((size_t) n >= sizeof(buf)) {
|
|
|
|
log_error("Got overly long cgroups agent message, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memchr(buf, 0, n)) {
|
|
|
|
log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
buf[n] = 0;
|
|
|
|
|
|
|
|
manager_notify_cgroup_empty(m, buf);
|
2017-09-08 17:24:57 +02:00
|
|
|
(void) bus_forward_agent_released(m, buf);
|
2016-05-04 20:43:23 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:46:45 +02:00
|
|
|
static bool manager_process_barrier_fd(char * const *tags, FDSet *fds) {
|
2020-04-28 16:09:27 +02:00
|
|
|
|
|
|
|
/* nothing else must be sent when using BARRIER=1 */
|
2020-05-10 18:46:45 +02:00
|
|
|
if (strv_contains(tags, "BARRIER=1")) {
|
|
|
|
if (strv_length(tags) == 1) {
|
|
|
|
if (fdset_size(fds) != 1)
|
|
|
|
log_warning("Got incorrect number of fds with BARRIER=1, closing them.");
|
|
|
|
} else
|
|
|
|
log_warning("Extra notification messages sent with BARRIER=1, ignoring everything.");
|
|
|
|
|
|
|
|
/* Drop the message if BARRIER=1 was found */
|
2020-04-28 16:09:27 +02:00
|
|
|
return true;
|
2020-05-10 18:46:45 +02:00
|
|
|
}
|
2020-04-28 16:09:27 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-05 12:20:22 +01:00
|
|
|
static void manager_invoke_notify_message(
|
|
|
|
Manager *m,
|
|
|
|
Unit *u,
|
|
|
|
const struct ucred *ucred,
|
2020-05-10 18:46:45 +02:00
|
|
|
char * const *tags,
|
2018-01-05 12:20:22 +01:00
|
|
|
FDSet *fds) {
|
|
|
|
|
2014-02-07 11:58:25 +01:00
|
|
|
assert(m);
|
|
|
|
assert(u);
|
2018-01-05 12:20:22 +01:00
|
|
|
assert(ucred);
|
2020-05-10 18:46:45 +02:00
|
|
|
assert(tags);
|
2014-02-07 11:58:25 +01:00
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
if (u->notifygen == m->notifygen) /* Already invoked on this same unit in this same iteration? */
|
2014-02-07 11:58:25 +01:00
|
|
|
return;
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
u->notifygen = m->notifygen;
|
|
|
|
|
2020-05-10 18:46:45 +02:00
|
|
|
if (UNIT_VTABLE(u)->notify_message)
|
2018-01-05 12:20:22 +01:00
|
|
|
UNIT_VTABLE(u)->notify_message(u, ucred, tags, fds);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
|
2020-05-10 18:46:45 +02:00
|
|
|
else if (DEBUG_LOGGING) {
|
|
|
|
_cleanup_free_ char *buf = NULL, *x = NULL, *y = NULL;
|
2016-09-29 16:07:41 +02:00
|
|
|
|
2020-05-10 18:46:45 +02:00
|
|
|
buf = strv_join(tags, ", ");
|
|
|
|
if (buf)
|
|
|
|
x = ellipsize(buf, 20, 90);
|
2016-09-29 16:07:41 +02:00
|
|
|
if (x)
|
2018-01-04 21:00:10 +01:00
|
|
|
y = cescape(x);
|
|
|
|
|
2016-09-29 16:07:41 +02:00
|
|
|
log_unit_debug(u, "Got notification message \"%s\", ignoring.", strnull(y));
|
|
|
|
}
|
2014-02-07 11:58:25 +01:00
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
2016-05-23 15:57:18 +02:00
|
|
|
|
2015-10-28 19:11:36 +01:00
|
|
|
_cleanup_fdset_free_ FDSet *fds = NULL;
|
2013-11-19 21:12:59 +01:00
|
|
|
Manager *m = userdata;
|
2015-10-28 19:11:36 +01:00
|
|
|
char buf[NOTIFY_BUFFER_MAX+1];
|
|
|
|
struct iovec iovec = {
|
|
|
|
.iov_base = buf,
|
|
|
|
.iov_len = sizeof(buf)-1,
|
|
|
|
};
|
2020-04-24 23:54:25 +02:00
|
|
|
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
|
|
|
|
CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
|
2015-10-28 19:11:36 +01:00
|
|
|
struct msghdr msghdr = {
|
|
|
|
.msg_iov = &iovec,
|
|
|
|
.msg_iovlen = 1,
|
|
|
|
.msg_control = &control,
|
|
|
|
.msg_controllen = sizeof(control),
|
|
|
|
};
|
|
|
|
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
struct ucred *ucred = NULL;
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
_cleanup_free_ Unit **array_copy = NULL;
|
2020-05-10 18:46:45 +02:00
|
|
|
_cleanup_strv_free_ char **tags = NULL;
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
Unit *u1, *u2, **array;
|
2015-10-28 19:11:36 +01:00
|
|
|
int r, *fd_array = NULL;
|
tree-wide: be more careful with the type of array sizes
Previously we were a bit sloppy with the index and size types of arrays,
we'd regularly use unsigned. While I don't think this ever resulted in
real issues I think we should be more careful there and follow a
stricter regime: unless there's a strong reason not to use size_t for
array sizes and indexes, size_t it should be. Any allocations we do
ultimately will use size_t anyway, and converting forth and back between
unsigned and size_t will always be a source of problems.
Note that on 32bit machines "unsigned" and "size_t" are equivalent, and
on 64bit machines our arrays shouldn't grow that large anyway, and if
they do we have a problem, however that kind of overly large allocation
we have protections for usually, but for overflows we do not have that
so much, hence let's add it.
So yeah, it's a story of the current code being already "good enough",
but I think some extra type hygiene is better.
This patch tries to be comprehensive, but it probably isn't and I missed
a few cases. But I guess we can cover that later as we notice it. Among
smaller fixes, this changes:
1. strv_length()' return type becomes size_t
2. the unit file changes array size becomes size_t
3. DNS answer and query array sizes become size_t
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=76745
2018-04-27 14:09:31 +02:00
|
|
|
size_t n_fds = 0;
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
bool found = false;
|
2010-06-16 05:10:31 +02:00
|
|
|
ssize_t n;
|
|
|
|
|
|
|
|
assert(m);
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m->notify_fd == fd);
|
|
|
|
|
|
|
|
if (revents != EPOLLIN) {
|
|
|
|
log_warning("Got unexpected poll event for notify fd.");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-06-16 05:10:31 +02:00
|
|
|
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
|
|
|
|
if (IN_SET(n, -EAGAIN, -EINTR))
|
|
|
|
return 0; /* Spurious wakeup, try again */
|
|
|
|
if (n < 0)
|
|
|
|
/* If this is any other, real error, then let's stop processing this socket. This of course
|
|
|
|
* means we won't take notification messages anymore, but that's still better than busy
|
|
|
|
* looping around this: being woken up over and over again but being unable to actually read
|
|
|
|
* the message off the socket. */
|
|
|
|
return log_error_errno(n, "Failed to receive notification message: %m");
|
2015-01-06 00:26:25 +01:00
|
|
|
|
2015-10-28 19:11:36 +01:00
|
|
|
CMSG_FOREACH(cmsg, &msghdr) {
|
|
|
|
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
2015-01-06 00:26:25 +01:00
|
|
|
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
assert(!fd_array);
|
2015-10-28 19:11:36 +01:00
|
|
|
fd_array = (int*) CMSG_DATA(cmsg);
|
|
|
|
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
|
2015-01-06 00:26:25 +01:00
|
|
|
|
2015-10-28 19:11:36 +01:00
|
|
|
} else if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
|
cmsg->cmsg_type == SCM_CREDENTIALS &&
|
|
|
|
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
|
2015-01-06 00:26:25 +01:00
|
|
|
|
tree-wide: use recvmsg_safe() at various places
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)
2020-04-23 09:40:03 +02:00
|
|
|
assert(!ucred);
|
2015-10-28 19:11:36 +01:00
|
|
|
ucred = (struct ucred*) CMSG_DATA(cmsg);
|
2015-01-06 00:26:25 +01:00
|
|
|
}
|
2015-10-28 19:11:36 +01:00
|
|
|
}
|
2015-01-06 00:26:25 +01:00
|
|
|
|
2015-10-28 19:11:36 +01:00
|
|
|
if (n_fds > 0) {
|
|
|
|
assert(fd_array);
|
2015-01-06 00:26:25 +01:00
|
|
|
|
2015-10-28 19:11:36 +01:00
|
|
|
r = fdset_new_array(&fds, fd_array, n_fds);
|
|
|
|
if (r < 0) {
|
|
|
|
close_many(fd_array, n_fds);
|
2016-09-29 19:44:34 +02:00
|
|
|
log_oom();
|
|
|
|
return 0;
|
2015-01-06 00:26:25 +01:00
|
|
|
}
|
2015-10-28 19:11:36 +01:00
|
|
|
}
|
2010-06-16 05:10:31 +02:00
|
|
|
|
2018-01-05 12:19:22 +01:00
|
|
|
if (!ucred || !pid_is_valid(ucred->pid)) {
|
2015-10-28 19:11:36 +01:00
|
|
|
log_warning("Received notify message without valid credentials. Ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-06-16 05:10:31 +02:00
|
|
|
|
2016-10-07 12:12:10 +02:00
|
|
|
if ((size_t) n >= sizeof(buf) || (msghdr.msg_flags & MSG_TRUNC)) {
|
2015-10-28 19:11:36 +01:00
|
|
|
log_warning("Received notify message exceeded maximum size. Ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-06-16 05:10:31 +02:00
|
|
|
|
2016-10-07 12:14:33 +02:00
|
|
|
/* As extra safety check, let's make sure the string we get doesn't contain embedded NUL bytes. We permit one
|
|
|
|
* trailing NUL byte in the message, but don't expect it. */
|
|
|
|
if (n > 1 && memchr(buf, 0, n-1)) {
|
|
|
|
log_warning("Received notify message with embedded NUL bytes. Ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:46:45 +02:00
|
|
|
/* Make sure it's NUL-terminated, then parse it to obtain the tags list */
|
2015-10-28 19:11:36 +01:00
|
|
|
buf[n] = 0;
|
2020-05-10 18:46:45 +02:00
|
|
|
tags = strv_split_newlines(buf);
|
|
|
|
if (!tags) {
|
|
|
|
log_oom();
|
|
|
|
return 0;
|
|
|
|
}
|
2010-06-16 05:10:31 +02:00
|
|
|
|
2020-04-28 16:09:27 +02:00
|
|
|
/* possibly a barrier fd, let's see */
|
2020-05-10 18:46:45 +02:00
|
|
|
if (manager_process_barrier_fd(tags, fds))
|
2020-04-28 16:09:27 +02:00
|
|
|
return 0;
|
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
/* Increase the generation counter used for filtering out duplicate unit invocations. */
|
|
|
|
m->notifygen++;
|
|
|
|
|
|
|
|
/* Notify every unit that might be interested, which might be multiple. */
|
2015-10-28 19:11:36 +01:00
|
|
|
u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
u2 = hashmap_get(m->watch_pids, PID_TO_PTR(ucred->pid));
|
|
|
|
array = hashmap_get(m->watch_pids, PID_TO_PTR(-ucred->pid));
|
|
|
|
if (array) {
|
|
|
|
size_t k = 0;
|
2014-02-07 11:58:25 +01:00
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
while (array[k])
|
|
|
|
k++;
|
2014-02-07 11:58:25 +01:00
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
array_copy = newdup(Unit*, array, k+1);
|
|
|
|
if (!array_copy)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
/* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle duplicate units
|
|
|
|
* make sure we only invoke each unit's handler once. */
|
|
|
|
if (u1) {
|
2020-05-10 18:46:45 +02:00
|
|
|
manager_invoke_notify_message(m, u1, ucred, tags, fds);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
if (u2) {
|
2020-05-10 18:46:45 +02:00
|
|
|
manager_invoke_notify_message(m, u2, ucred, tags, fds);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
if (array_copy)
|
|
|
|
for (size_t i = 0; array_copy[i]; i++) {
|
2020-05-10 18:46:45 +02:00
|
|
|
manager_invoke_notify_message(m, array_copy[i], ucred, tags, fds);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
found = true;
|
|
|
|
}
|
2010-06-16 05:10:31 +02:00
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
if (!found)
|
|
|
|
log_warning("Cannot find unit for notify message of PID "PID_FMT", ignoring.", ucred->pid);
|
2015-01-06 00:26:25 +01:00
|
|
|
|
2015-10-28 19:11:36 +01:00
|
|
|
if (fdset_size(fds) > 0)
|
2016-09-30 13:35:07 +02:00
|
|
|
log_warning("Got extra auxiliary fds with notification message, closing them.");
|
2010-06-16 05:10:31 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
static void manager_invoke_sigchld_event(
|
|
|
|
Manager *m,
|
|
|
|
Unit *u,
|
|
|
|
const siginfo_t *si) {
|
2016-06-30 21:12:18 +02:00
|
|
|
|
2014-02-07 11:58:25 +01:00
|
|
|
assert(m);
|
|
|
|
assert(u);
|
|
|
|
assert(si);
|
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
/* Already invoked the handler of this unit in this iteration? Then don't process this again */
|
|
|
|
if (u->sigchldgen == m->sigchldgen)
|
|
|
|
return;
|
|
|
|
u->sigchldgen = m->sigchldgen;
|
2014-02-07 11:58:25 +01:00
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
log_unit_debug(u, "Child "PID_FMT" belongs to %s.", si->si_pid, u->id);
|
2014-02-07 11:58:25 +01:00
|
|
|
unit_unwatch_pid(u, si->si_pid);
|
2016-03-25 16:38:50 +01:00
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
if (UNIT_VTABLE(u)->sigchld_event)
|
|
|
|
UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
|
2014-02-07 11:58:25 +01:00
|
|
|
}
|
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
static int manager_dispatch_sigchld(sd_event_source *source, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
siginfo_t si = {};
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(source);
|
2010-01-24 00:39:29 +01:00
|
|
|
assert(m);
|
|
|
|
|
2019-05-20 13:37:03 +02:00
|
|
|
/* First we call waitid() for a PID and do not reap the zombie. That way we can still access /proc/$PID for it
|
2018-01-23 18:18:13 +01:00
|
|
|
* while it is a zombie. */
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
|
2010-01-27 04:31:52 +01:00
|
|
|
|
2018-02-13 19:04:31 +01:00
|
|
|
if (errno != ECHILD)
|
|
|
|
log_error_errno(errno, "Failed to peek for child with waitid(), ignoring: %m");
|
2010-01-27 04:31:52 +01:00
|
|
|
|
2018-02-13 19:04:31 +01:00
|
|
|
goto turn_off;
|
2018-01-23 18:18:13 +01:00
|
|
|
}
|
2010-04-13 02:05:27 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
if (si.si_pid <= 0)
|
|
|
|
goto turn_off;
|
|
|
|
|
|
|
|
if (IN_SET(si.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) {
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
_cleanup_free_ Unit **array_copy = NULL;
|
2018-01-23 18:18:13 +01:00
|
|
|
_cleanup_free_ char *name = NULL;
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
Unit *u1, *u2, **array;
|
2018-01-23 18:18:13 +01:00
|
|
|
|
|
|
|
(void) 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)));
|
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
/* Increase the generation counter used for filtering out duplicate unit invocations */
|
|
|
|
m->sigchldgen++;
|
|
|
|
|
|
|
|
/* And now figure out the unit this belongs to, it might be multiple... */
|
2018-01-23 18:18:13 +01:00
|
|
|
u1 = manager_get_unit_by_pid_cgroup(m, si.si_pid);
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
u2 = hashmap_get(m->watch_pids, PID_TO_PTR(si.si_pid));
|
|
|
|
array = hashmap_get(m->watch_pids, PID_TO_PTR(-si.si_pid));
|
|
|
|
if (array) {
|
|
|
|
size_t n = 0;
|
|
|
|
|
2019-04-27 02:22:40 +02:00
|
|
|
/* Count how many entries the array has */
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
while (array[n])
|
|
|
|
n++;
|
|
|
|
|
|
|
|
/* Make a copy of the array so that we don't trip up on the array changing beneath us */
|
|
|
|
array_copy = newdup(Unit*, array, n+1);
|
|
|
|
if (!array_copy)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally, execute them all. Note that u1, u2 and the array might contain duplicates, but
|
|
|
|
* that's fine, manager_invoke_sigchld_event() will ensure we only invoke the handlers once for
|
|
|
|
* each iteration. */
|
2019-05-19 15:52:02 +02:00
|
|
|
if (u1) {
|
|
|
|
/* We check for oom condition, in case we got SIGCHLD before the oom notification.
|
|
|
|
* We only do this for the cgroup the PID belonged to. */
|
|
|
|
(void) unit_check_oom(u1);
|
|
|
|
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
manager_invoke_sigchld_event(m, u1, &si);
|
2019-05-19 15:52:02 +02:00
|
|
|
}
|
core: rework how we track which PIDs to watch for a unit
Previously, we'd maintain two hashmaps keyed by PIDs, pointing to Unit
interested in SIGCHLD events for them. This scheme allowed a specific
PID to be watched by exactly 0, 1 or 2 units.
With this rework this is replaced by a single hashmap which is primarily
keyed by the PID and points to a Unit interested in it. However, it
optionally also keyed by the negated PID, in which case it points to a
NULL terminated array of additional Unit objects also interested. This
scheme means arbitrary numbers of Units may now watch the same PID.
Runtime and memory behaviour should not be impact by this change, as for
the common case (i.e. each PID only watched by a single unit) behaviour
stays the same, but for the uncommon case (a PID watched by more than
one unit) we only pay with a single additional memory allocation for the
array.
Why this all? Primarily, because allowing exactly two units to watch a
specific PID is not sufficient for some niche cases, as processes can
belong to more than one unit these days:
1. sd_notify() with MAINPID= can be used to attach a process from a
different cgroup to multiple units.
2. Similar, the PIDFile= setting in unit files can be used for similar
setups,
3. By creating a scope unit a main process of a service may join a
different unit, too.
4. On cgroupsv1 we frequently end up watching all processes remaining in
a scope, and if a process opens lots of scopes one after the other it
might thus end up being watch by many of them.
This patch hence removes the 2-unit-per-PID limit. It also makes a
couple of other changes, some of them quite relevant:
- manager_get_unit_by_pid() (and the bus call wrapping it) when there's
ambiguity will prefer returning the Unit the process belongs to based on
cgroup membership, and only check the watch-pids hashmap if that
fails. This change in logic is probably more in line with what people
expect and makes things more stable as each process can belong to
exactly one cgroup only.
- Every SIGCHLD event is now dispatched to all units interested in its
PID. Previously, there was some magic conditionalization: the SIGCHLD
would only be dispatched to the unit if it was only interested in a
single PID only, or the PID belonged to the control or main PID or we
didn't dispatch a signle SIGCHLD to the unit in the current event loop
iteration yet. These rules were quite arbitrary and also redundant as
the the per-unit handlers would filter the PIDs anyway a second time.
With this change we'll hence relax the rules: all we do now is
dispatch every SIGCHLD event exactly once to each unit interested in
it, and it's up to the unit to then use or ignore this. We use a
generation counter in the unit to ensure that we only invoke the unit
handler once for each event, protecting us from confusion if a unit is
both associated with a specific PID through cgroup membership and
through the "watch_pids" logic. It also protects us from being
confused if the "watch_pids" hashmap is altered while we are
dispatching to it (which is a very likely case).
- sd_notify() message dispatching has been reworked to be very similar
to SIGCHLD handling now. A generation counter is used for dispatching
as well.
This also adds a new test that validates that "watch_pid" registration
and unregstration works correctly.
2018-01-12 13:41:05 +01:00
|
|
|
if (u2)
|
|
|
|
manager_invoke_sigchld_event(m, u2, &si);
|
|
|
|
if (array_copy)
|
|
|
|
for (size_t i = 0; array_copy[i]; i++)
|
|
|
|
manager_invoke_sigchld_event(m, array_copy[i], &si);
|
2018-01-23 18:18:13 +01:00
|
|
|
}
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
/* And now, we actually reap the zombie. */
|
|
|
|
if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
|
|
|
|
log_error_errno(errno, "Failed to dequeue child, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
return 0;
|
2010-06-16 05:10:31 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
turn_off:
|
|
|
|
/* All children processed for now, turn off event source */
|
2010-04-13 02:05:27 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
r = sd_event_source_set_enabled(m->sigchld_event_source, SD_EVENT_OFF);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to disable SIGCHLD event source: %m");
|
2010-01-24 00:39:29 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-02 17:19:22 +02:00
|
|
|
static void manager_start_target(Manager *m, const char *name, JobMode mode) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2010-04-13 01:59:06 +02:00
|
|
|
int r;
|
2010-07-08 02:43:18 +02:00
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_debug("Activating special unit %s", name);
|
2010-07-10 04:50:19 +02:00
|
|
|
|
2019-03-22 20:57:30 +01:00
|
|
|
r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
|
2013-01-02 22:03:35 +01:00
|
|
|
if (r < 0)
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
|
2010-04-13 01:59:06 +02:00
|
|
|
}
|
|
|
|
|
2016-10-07 03:08:21 +02:00
|
|
|
static void manager_handle_ctrl_alt_del(Manager *m) {
|
|
|
|
/* If the user presses C-A-D more than
|
|
|
|
* 7 times within 2s, we reboot/shutdown immediately,
|
|
|
|
* unless it was disabled in system.conf */
|
|
|
|
|
2018-05-11 11:16:52 +02:00
|
|
|
if (ratelimit_below(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE)
|
2016-10-07 03:08:21 +02:00
|
|
|
manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
|
2016-10-18 12:16:32 +02:00
|
|
|
else
|
2018-11-16 11:41:18 +01:00
|
|
|
emergency_action(m, m->cad_burst_action, EMERGENCY_ACTION_WARN, NULL, -1,
|
2016-10-18 12:16:32 +02:00
|
|
|
"Ctrl-Alt-Del was pressed more than 7 times within 2s");
|
2016-10-07 03:08:21 +02:00
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
2010-01-24 00:39:29 +01:00
|
|
|
ssize_t n;
|
|
|
|
struct signalfd_siginfo sfsi;
|
2015-07-29 20:31:07 +02:00
|
|
|
int r;
|
2010-01-24 00:39:29 +01:00
|
|
|
|
|
|
|
assert(m);
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m->signal_fd == fd);
|
|
|
|
|
|
|
|
if (revents != EPOLLIN) {
|
|
|
|
log_warning("Got unexpected events from signal file descriptor.");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
n = read(m->signal_fd, &sfsi, sizeof(sfsi));
|
|
|
|
if (n != sizeof(sfsi)) {
|
|
|
|
if (n >= 0) {
|
|
|
|
log_warning("Truncated read from signal fd (%zu bytes), ignoring!", n);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
if (IN_SET(errno, EINTR, EAGAIN))
|
|
|
|
return 0;
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
/* We return an error here, which will kill this handler,
|
|
|
|
* to avoid a busy loop on read error. */
|
|
|
|
return log_error_errno(errno, "Reading from signal fd failed: %m");
|
|
|
|
}
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
|
|
|
|
(sfsi.ssi_signo == SIGTERM && MANAGER_IS_USER(m))
|
|
|
|
? LOG_DEBUG : LOG_INFO,
|
|
|
|
&sfsi);
|
2010-07-10 04:50:19 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
switch (sfsi.ssi_signo) {
|
2010-01-27 04:36:30 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case SIGCHLD:
|
|
|
|
r = sd_event_source_set_enabled(m->sigchld_event_source, SD_EVENT_ON);
|
|
|
|
if (r < 0)
|
2018-02-13 19:04:31 +01:00
|
|
|
log_warning_errno(r, "Failed to enable SIGCHLD event source, ignoring: %m");
|
2010-01-27 04:36:30 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
2010-02-13 01:17:08 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case SIGTERM:
|
|
|
|
if (MANAGER_IS_SYSTEM(m)) {
|
2018-03-16 20:46:39 +01:00
|
|
|
/* This is for compatibility with the original sysvinit */
|
2018-10-09 16:02:31 +02:00
|
|
|
if (verify_run_space_and_log("Refusing to reexecute") < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
m->objective = MANAGER_REEXECUTE;
|
2010-05-24 22:31:38 +02:00
|
|
|
break;
|
2018-01-23 18:18:13 +01:00
|
|
|
}
|
2010-02-13 01:17:08 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
_fallthrough_;
|
|
|
|
case SIGINT:
|
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
manager_handle_ctrl_alt_del(m);
|
|
|
|
else
|
|
|
|
manager_start_target(m, SPECIAL_EXIT_TARGET,
|
|
|
|
JOB_REPLACE_IRREVERSIBLY);
|
|
|
|
break;
|
2010-02-13 01:17:08 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case SIGWINCH:
|
2018-03-16 20:46:39 +01:00
|
|
|
/* This is a nop on non-init */
|
2018-01-23 18:18:13 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
|
2010-02-13 01:17:08 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
2010-02-13 01:17:08 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case SIGPWR:
|
2018-03-16 20:46:39 +01:00
|
|
|
/* This is a nop on non-init */
|
2018-01-23 18:18:13 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
|
2010-01-27 05:31:53 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
2010-04-13 03:20:22 +02:00
|
|
|
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
case SIGUSR1:
|
|
|
|
if (manager_dbus_is_running(m, false)) {
|
2018-01-23 18:18:13 +01:00
|
|
|
log_info("Trying to reconnect to bus...");
|
|
|
|
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
(void) bus_init_api(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
(void) bus_init_system(m);
|
|
|
|
} else {
|
|
|
|
log_info("Starting D-Bus service...");
|
2018-01-23 18:18:13 +01:00
|
|
|
manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
|
|
|
|
}
|
2010-04-13 03:20:22 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGUSR2: {
|
|
|
|
_cleanup_free_ char *dump = NULL;
|
|
|
|
|
|
|
|
r = manager_get_dump_string(m, &dump);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(errno, "Failed to acquire manager dump: %m");
|
2010-04-13 03:20:22 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
log_dump(LOG_INFO, dump);
|
|
|
|
break;
|
|
|
|
}
|
2010-06-04 19:45:53 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case SIGHUP:
|
2018-10-09 16:02:31 +02:00
|
|
|
if (verify_run_space_and_log("Refusing to reload") < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
m->objective = MANAGER_RELOAD;
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
|
|
|
/* Starting SIGRTMIN+0 */
|
|
|
|
static const struct {
|
|
|
|
const char *target;
|
|
|
|
JobMode mode;
|
|
|
|
} target_table[] = {
|
|
|
|
[0] = { SPECIAL_DEFAULT_TARGET, JOB_ISOLATE },
|
|
|
|
[1] = { SPECIAL_RESCUE_TARGET, JOB_ISOLATE },
|
|
|
|
[2] = { SPECIAL_EMERGENCY_TARGET, JOB_ISOLATE },
|
|
|
|
[3] = { SPECIAL_HALT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
|
|
|
[4] = { SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
|
|
|
[5] = { SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
|
|
|
[6] = { SPECIAL_KEXEC_TARGET, JOB_REPLACE_IRREVERSIBLY },
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
|
2018-10-09 15:42:19 +02:00
|
|
|
static const ManagerObjective objective_table[] = {
|
2018-01-23 18:18:13 +01:00
|
|
|
[0] = MANAGER_HALT,
|
|
|
|
[1] = MANAGER_POWEROFF,
|
|
|
|
[2] = MANAGER_REBOOT,
|
|
|
|
[3] = MANAGER_KEXEC,
|
|
|
|
};
|
manager: flush memory stream before using the buffer
When the manager receives a SIGUSR2 signal, it opens a memory stream
with open_memstream(), uses the returned file handle for logging, and
dumps the logged content with log_dump().
However, the char* buffer is only safe to use after the file handle has
been flushed with fflush, as the man pages states:
When the stream is closed (fclose(3)) or flushed (fflush(3)), the
locations pointed to by ptr and sizeloc are updated to contain,
respectively, a pointer to the buffer and the current size of the
buffer.
These values remain valid only as long as the caller performs no
further output on the stream. If further output is performed, then the
stream must again be flushed before trying to access these variables.
Without that call, dump remains NULL and the daemon crashes in
log_dump().
2014-03-07 14:43:59 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
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].target,
|
|
|
|
target_table[idx].mode);
|
2010-04-24 04:27:05 +02:00
|
|
|
break;
|
2010-06-04 19:45:53 +02:00
|
|
|
}
|
2010-04-24 04:27:05 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
|
2018-10-09 15:42:19 +02:00
|
|
|
(int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(objective_table)) {
|
|
|
|
m->objective = objective_table[sfsi.ssi_signo - SIGRTMIN - 13];
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (sfsi.ssi_signo - SIGRTMIN) {
|
|
|
|
|
|
|
|
case 20:
|
2020-06-04 13:25:25 +02:00
|
|
|
manager_override_show_status(m, SHOW_STATUS_YES, "signal");
|
2010-04-21 03:27:44 +02:00
|
|
|
break;
|
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case 21:
|
2020-06-04 13:25:25 +02:00
|
|
|
manager_override_show_status(m, SHOW_STATUS_NO, "signal");
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
2010-06-17 23:22:56 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case 22:
|
2018-05-30 17:57:23 +02:00
|
|
|
manager_override_log_level(m, LOG_DEBUG);
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 23:
|
2018-05-30 17:57:23 +02:00
|
|
|
manager_restore_original_log_level(m);
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
2010-10-14 00:54:48 +02:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
case 24:
|
|
|
|
if (MANAGER_IS_USER(m)) {
|
2018-10-09 15:42:19 +02:00
|
|
|
m->objective = MANAGER_EXIT;
|
2018-01-23 18:18:13 +01:00
|
|
|
return 0;
|
2011-02-09 12:12:30 +01:00
|
|
|
}
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
/* This is a nop on init */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 26:
|
|
|
|
case 29: /* compatibility: used to be mapped to LOG_TARGET_SYSLOG_OR_KMSG */
|
2018-06-01 18:21:03 +02:00
|
|
|
manager_restore_original_log_target(m);
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 27:
|
2018-06-01 18:21:03 +02:00
|
|
|
manager_override_log_target(m, LOG_TARGET_CONSOLE);
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 28:
|
2018-06-01 18:21:03 +02:00
|
|
|
manager_override_log_target(m, LOG_TARGET_KMSG);
|
2018-01-23 18:18:13 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
|
|
|
|
}
|
|
|
|
}}
|
2010-01-26 04:18:44 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
Unit *u;
|
2010-01-26 04:18:44 +01:00
|
|
|
|
|
|
|
assert(m);
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m->time_change_fd == fd);
|
2010-01-26 04:18:44 +01:00
|
|
|
|
2016-12-18 13:21:19 +01:00
|
|
|
log_struct(LOG_DEBUG,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_MESSAGE("Time has been changed"));
|
2010-01-26 04:18:44 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
/* Restart the watch */
|
2018-05-28 21:32:03 +02:00
|
|
|
(void) manager_setup_time_change(m);
|
2010-10-18 23:09:09 +02:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(u, m->units)
|
2013-11-19 21:12:59 +01:00
|
|
|
if (UNIT_VTABLE(u)->time_change)
|
|
|
|
UNIT_VTABLE(u)->time_change(u);
|
2010-02-01 03:33:24 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2010-02-01 03:33:24 +01:00
|
|
|
|
2018-05-28 21:33:10 +02:00
|
|
|
static int manager_dispatch_timezone_change(
|
|
|
|
sd_event_source *source,
|
|
|
|
const struct inotify_event *e,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
Manager *m = userdata;
|
|
|
|
int changed;
|
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
log_debug("inotify event for /etc/localtime");
|
|
|
|
|
|
|
|
changed = manager_read_timezone_stat(m);
|
2018-11-16 14:42:14 +01:00
|
|
|
if (changed <= 0)
|
2018-05-28 21:33:10 +02:00
|
|
|
return changed;
|
|
|
|
|
|
|
|
/* Something changed, restart the watch, to ensure we watch the new /etc/localtime if it changed */
|
|
|
|
(void) manager_setup_timezone_change(m);
|
|
|
|
|
|
|
|
/* Read the new timezone */
|
|
|
|
tzset();
|
|
|
|
|
|
|
|
log_debug("Timezone has been changed (now: %s).", tzname[daylight]);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(u, m->units)
|
2018-05-28 21:33:10 +02:00
|
|
|
if (UNIT_VTABLE(u)->timezone_change)
|
|
|
|
UNIT_VTABLE(u)->timezone_change(u);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
2012-11-25 00:32:40 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m);
|
|
|
|
assert(m->idle_pipe[2] == fd);
|
2012-11-25 00:32:40 +01:00
|
|
|
|
2018-01-24 19:52:14 +01:00
|
|
|
/* There's at least one Type=idle child that just gave up on us waiting for the boot process to complete. Let's
|
|
|
|
* now turn off any further console output if there's at least one service that needs console access, so that
|
|
|
|
* from now on our own output should not spill into that service's output anymore. After all, we support
|
|
|
|
* Type=idle only to beautify console output and it generally is set on services that want to own the console
|
|
|
|
* exclusively without our interference. */
|
2013-11-19 21:12:59 +01:00
|
|
|
m->no_console_output = m->n_on_console > 0;
|
2013-02-28 00:03:22 +01:00
|
|
|
|
2018-01-24 19:52:14 +01:00
|
|
|
/* Acknowledge the child's request, and let all all other children know too that they shouldn't wait any longer
|
|
|
|
* by closing the pipes towards them, which is what they are waiting for. */
|
2013-11-19 21:12:59 +01:00
|
|
|
manager_close_idle_pipe(m);
|
2013-02-28 00:03:22 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
2014-01-27 07:15:27 +01:00
|
|
|
int r;
|
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished,
the manager, as before, signals idling Type=idle jobs to continue.
However, if the boot takes too long, idling jobs signal the manager
that they have had enough, wait a tiny bit more, and continue, taking
ownership of the console. The manager, when signalled that Type=idle
jobs are done, makes a note and will not write to the console anymore.
This is a cosmetic issue, but quite noticable, so let's just fix it.
Based on Harald Hoyer's patch.
https://bugs.freedesktop.org/show_bug.cgi?id=54247
http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
2013-07-16 03:34:57 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
assert(m);
|
2014-01-27 07:15:27 +01:00
|
|
|
assert(source);
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
manager_print_jobs_in_progress(m);
|
2014-01-27 07:15:27 +01:00
|
|
|
|
2020-07-28 11:18:26 +02:00
|
|
|
r = sd_event_source_set_time_relative(source, JOBS_IN_PROGRESS_PERIOD_USEC);
|
2014-01-27 07:15:27 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
|
2010-01-24 00:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int manager_loop(Manager *m) {
|
2019-09-19 17:41:20 +02:00
|
|
|
RateLimit rl = { .interval = 1*USEC_PER_SEC, .burst = 50000 };
|
2010-01-24 00:39:29 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2018-10-09 17:58:08 +02:00
|
|
|
assert(m->objective == MANAGER_OK); /* Ensure manager_startup() has been called */
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2010-09-21 04:14:38 +02:00
|
|
|
manager_check_finished(m);
|
|
|
|
|
2018-01-23 18:18:13 +01:00
|
|
|
/* There might still be some zombies hanging around from before we were exec()'ed. Let's reap them. */
|
|
|
|
r = sd_event_source_set_enabled(m->sigchld_event_source, SD_EVENT_ON);
|
2012-04-05 22:08:10 +02:00
|
|
|
if (r < 0)
|
2018-01-23 18:18:13 +01:00
|
|
|
return log_error_errno(r, "Failed to enable SIGCHLD event source: %m");
|
2010-05-18 04:16:33 +02:00
|
|
|
|
2018-10-09 15:42:19 +02:00
|
|
|
while (m->objective == MANAGER_OK) {
|
2020-04-22 16:16:47 +02:00
|
|
|
usec_t wait_usec, watchdog_usec;
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2020-04-22 16:16:47 +02:00
|
|
|
watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
|
|
|
|
if (timestamp_is_set(watchdog_usec))
|
2012-04-05 22:08:10 +02:00
|
|
|
watchdog_ping();
|
|
|
|
|
2018-05-11 11:16:52 +02:00
|
|
|
if (!ratelimit_below(&rl)) {
|
2010-02-01 03:33:24 +01:00
|
|
|
/* Yay, something is going seriously wrong, pause a little */
|
|
|
|
log_warning("Looping too fast. Throttling execution a little.");
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
|
2010-05-16 03:57:56 +02:00
|
|
|
if (manager_dispatch_load_queue(m) > 0)
|
2010-04-06 02:43:58 +02:00
|
|
|
continue;
|
|
|
|
|
2016-11-15 19:32:50 +01:00
|
|
|
if (manager_dispatch_gc_job_queue(m) > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (manager_dispatch_gc_unit_queue(m) > 0)
|
2010-04-21 06:01:13 +02:00
|
|
|
continue;
|
|
|
|
|
2013-07-02 17:41:57 +02:00
|
|
|
if (manager_dispatch_cleanup_queue(m) > 0)
|
2010-02-05 00:38:41 +01:00
|
|
|
continue;
|
2010-01-26 04:18:44 +01:00
|
|
|
|
2017-09-26 22:15:02 +02:00
|
|
|
if (manager_dispatch_cgroup_realize_queue(m) > 0)
|
2010-02-05 00:38:41 +01:00
|
|
|
continue;
|
|
|
|
|
2018-08-09 16:26:27 +02:00
|
|
|
if (manager_dispatch_stop_when_unneeded_queue(m) > 0)
|
|
|
|
continue;
|
|
|
|
|
2010-02-05 00:38:41 +01:00
|
|
|
if (manager_dispatch_dbus_queue(m) > 0)
|
2010-02-01 03:33:24 +01:00
|
|
|
continue;
|
|
|
|
|
2020-04-02 09:10:55 +02:00
|
|
|
/* Sleep for watchdog runtime wait time */
|
2020-04-22 16:16:47 +02:00
|
|
|
if (timestamp_is_set(watchdog_usec))
|
2020-04-02 09:10:55 +02:00
|
|
|
wait_usec = watchdog_runtime_wait();
|
|
|
|
else
|
2014-07-29 12:23:31 +02:00
|
|
|
wait_usec = USEC_INFINITY;
|
2010-01-24 00:39:29 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
r = sd_event_run(m->event, wait_usec);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to run event loop: %m");
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
2010-01-27 22:40:10 +01:00
|
|
|
|
2018-10-09 15:42:19 +02:00
|
|
|
return m->objective;
|
2010-01-23 22:56:47 +01:00
|
|
|
}
|
2010-02-01 03:33:24 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u) {
|
2013-07-02 01:35:08 +02:00
|
|
|
_cleanup_free_ char *n = NULL;
|
2016-08-30 23:18:46 +02:00
|
|
|
sd_id128_t invocation_id;
|
2010-02-01 03:33:24 +01:00
|
|
|
Unit *u;
|
2012-05-21 12:54:34 +02:00
|
|
|
int r;
|
2010-02-01 03:33:24 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(s);
|
|
|
|
assert(_u);
|
|
|
|
|
2013-07-02 01:35:08 +02:00
|
|
|
r = unit_name_from_dbus_path(s, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-02-01 03:33:24 +01:00
|
|
|
|
2016-08-30 23:18:46 +02:00
|
|
|
/* Permit addressing units by invocation ID: if the passed bus path is suffixed by a 128bit ID then we use it
|
|
|
|
* as invocation ID. */
|
|
|
|
r = sd_id128_from_string(n, &invocation_id);
|
|
|
|
if (r >= 0) {
|
|
|
|
u = hashmap_get(m->units_by_invocation_id, &invocation_id);
|
|
|
|
if (u) {
|
|
|
|
*_u = u;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-13 22:04:12 +02:00
|
|
|
return sd_bus_error_setf(e, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID,
|
|
|
|
"No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.",
|
|
|
|
SD_ID128_FORMAT_VAL(invocation_id));
|
2016-08-30 23:18:46 +02:00
|
|
|
}
|
|
|
|
|
2017-06-21 20:45:23 +02:00
|
|
|
/* If this didn't work, we check if this is a unit name */
|
2018-05-13 22:04:12 +02:00
|
|
|
if (!unit_name_is_valid(n, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
|
|
|
|
_cleanup_free_ char *nn = NULL;
|
|
|
|
|
|
|
|
nn = cescape(n);
|
|
|
|
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS,
|
|
|
|
"Unit name %s is neither a valid invocation ID nor unit name.", strnull(nn));
|
|
|
|
}
|
2017-06-21 20:45:23 +02:00
|
|
|
|
2012-05-21 12:54:34 +02:00
|
|
|
r = manager_load_unit(m, n, NULL, e, &u);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-02-01 03:33:24 +01:00
|
|
|
|
|
|
|
*_u = u;
|
|
|
|
return 0;
|
|
|
|
}
|
2010-02-02 12:42:08 +01:00
|
|
|
|
|
|
|
int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
|
2013-11-19 21:12:59 +01:00
|
|
|
const char *p;
|
2010-02-02 12:42:08 +01:00
|
|
|
unsigned id;
|
2013-11-19 21:12:59 +01:00
|
|
|
Job *j;
|
2010-02-02 12:42:08 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(s);
|
|
|
|
assert(_j);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
p = startswith(s, "/org/freedesktop/systemd1/job/");
|
|
|
|
if (!p)
|
2010-02-02 12:42:08 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
r = safe_atou(p, &id);
|
2012-11-25 00:32:40 +01:00
|
|
|
if (r < 0)
|
2010-02-02 12:42:08 +01:00
|
|
|
return r;
|
|
|
|
|
2012-11-25 00:32:40 +01:00
|
|
|
j = manager_get_job(m, id);
|
|
|
|
if (!j)
|
2010-02-02 12:42:08 +01:00
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
*_j = j;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2010-02-12 21:57:39 +01:00
|
|
|
|
2010-08-11 01:43:23 +02:00
|
|
|
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
|
2010-04-10 17:53:17 +02:00
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_AUDIT
|
2014-01-12 21:55:10 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2014-11-04 00:47:44 +01:00
|
|
|
const char *msg;
|
2015-04-30 20:21:00 +02:00
|
|
|
int audit_fd, r;
|
2010-04-10 17:53:17 +02:00
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
2015-10-28 18:23:26 +01:00
|
|
|
return;
|
|
|
|
|
2012-10-02 23:40:09 +02:00
|
|
|
audit_fd = get_audit_fd();
|
|
|
|
if (audit_fd < 0)
|
2010-04-10 17:53:17 +02:00
|
|
|
return;
|
|
|
|
|
2010-08-12 03:51:58 +02:00
|
|
|
/* Don't generate audit events if the service was already
|
|
|
|
* started and we're just deserializing */
|
2016-02-24 21:36:09 +01:00
|
|
|
if (MANAGER_IS_RELOADING(m))
|
2010-08-12 03:51:58 +02:00
|
|
|
return;
|
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
if (u->type != UNIT_SERVICE)
|
2011-03-18 04:31:22 +01:00
|
|
|
return;
|
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
r = unit_name_to_prefix_and_instance(u->id, &p);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to extract prefix and instance of unit name: %m");
|
2010-04-10 17:53:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-03 02:05:59 +01:00
|
|
|
msg = strjoina("unit=", p);
|
2014-11-04 00:47:44 +01:00
|
|
|
if (audit_log_user_comm_message(audit_fd, type, msg, "systemd", NULL, NULL, NULL, success) < 0) {
|
|
|
|
if (errno == EPERM)
|
2011-03-14 17:48:34 +01:00
|
|
|
/* We aren't allowed to send audit messages?
|
2012-04-13 17:17:56 +02:00
|
|
|
* Then let's not retry again. */
|
2012-10-02 23:40:09 +02:00
|
|
|
close_audit_fd();
|
2014-11-04 00:47:44 +01:00
|
|
|
else
|
2014-11-28 19:29:59 +01:00
|
|
|
log_warning_errno(errno, "Failed to send audit message: %m");
|
2011-03-14 17:48:34 +01:00
|
|
|
}
|
2010-08-11 01:43:23 +02:00
|
|
|
#endif
|
2010-04-10 17:53:17 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-10-06 03:55:49 +02:00
|
|
|
void manager_send_unit_plymouth(Manager *m, Unit *u) {
|
2016-05-05 22:24:36 +02:00
|
|
|
static const union sockaddr_union sa = PLYMOUTH_SOCKET;
|
2014-01-12 21:55:10 +01:00
|
|
|
_cleanup_free_ char *message = NULL;
|
|
|
|
_cleanup_close_ int fd = -1;
|
2016-05-05 22:24:36 +02:00
|
|
|
int n = 0;
|
2010-10-06 03:55:49 +02:00
|
|
|
|
|
|
|
/* Don't generate plymouth events if the service was already
|
|
|
|
* started and we're just deserializing */
|
2016-02-24 21:36:09 +01:00
|
|
|
if (MANAGER_IS_RELOADING(m))
|
2010-10-06 03:55:49 +02:00
|
|
|
return;
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
2010-10-06 03:55:49 +02:00
|
|
|
return;
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
if (detect_container() > 0)
|
2013-11-20 03:44:11 +01:00
|
|
|
return;
|
|
|
|
|
2017-09-29 09:58:22 +02:00
|
|
|
if (!IN_SET(u->type, UNIT_SERVICE, UNIT_MOUNT, UNIT_SWAP))
|
2010-10-06 03:55:49 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* We set SOCK_NONBLOCK here so that we rather drop the
|
|
|
|
* message then wait for plymouth */
|
2013-03-25 00:45:16 +01:00
|
|
|
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
|
|
|
if (fd < 0) {
|
2014-11-28 19:29:59 +01:00
|
|
|
log_error_errno(errno, "socket() failed: %m");
|
2010-10-06 03:55:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-05 22:24:36 +02:00
|
|
|
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
|
2019-03-19 15:39:34 +01:00
|
|
|
if (!IN_SET(errno, EAGAIN, ENOENT) && !ERRNO_IS_DISCONNECT(errno))
|
2014-11-28 19:29:59 +01:00
|
|
|
log_error_errno(errno, "connect() failed: %m");
|
2014-01-12 21:55:10 +01:00
|
|
|
return;
|
2010-10-06 03:55:49 +02:00
|
|
|
}
|
|
|
|
|
2012-01-15 12:04:08 +01:00
|
|
|
if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
|
2012-07-25 23:55:59 +02:00
|
|
|
log_oom();
|
2014-01-12 21:55:10 +01:00
|
|
|
return;
|
2010-10-06 03:55:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
errno = 0;
|
2014-01-12 21:55:10 +01:00
|
|
|
if (write(fd, message, n + 1) != n + 1)
|
2019-03-19 15:39:34 +01:00
|
|
|
if (!IN_SET(errno, EAGAIN, ENOENT) && !ERRNO_IS_DISCONNECT(errno))
|
2014-11-28 19:29:59 +01:00
|
|
|
log_error_errno(errno, "Failed to write Plymouth message: %m");
|
2010-10-06 03:55:49 +02:00
|
|
|
}
|
|
|
|
|
2010-07-20 20:54:33 +02:00
|
|
|
int manager_open_serialization(Manager *m, FILE **_f) {
|
2020-03-31 11:29:37 +02:00
|
|
|
_cleanup_close_ int fd = -1;
|
2010-04-21 03:27:44 +02:00
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
assert(_f);
|
|
|
|
|
2017-02-12 00:33:16 +01:00
|
|
|
fd = open_serialization_fd("systemd-state");
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2020-03-31 11:29:37 +02:00
|
|
|
f = take_fdopen(&fd, "w+");
|
|
|
|
if (!f)
|
2010-04-21 03:27:44 +02:00
|
|
|
return -errno;
|
|
|
|
|
|
|
|
*_f = f;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:35:28 +02:00
|
|
|
static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
|
|
|
|
|
|
|
|
if (!in_initrd())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* The following timestamps only apply to the host system, hence only serialize them there */
|
|
|
|
return !IN_SET(t,
|
|
|
|
MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
|
|
|
|
MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
|
|
|
|
MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
|
|
|
|
MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
|
|
|
|
}
|
|
|
|
|
2020-04-27 08:59:43 +02:00
|
|
|
#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
|
|
|
|
|
|
|
|
static void manager_serialize_uid_refs_internal(
|
|
|
|
Manager *m,
|
|
|
|
FILE *f,
|
|
|
|
Hashmap **uid_refs,
|
|
|
|
const char *field_name) {
|
|
|
|
|
|
|
|
void *p, *k;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(f);
|
|
|
|
assert(uid_refs);
|
|
|
|
assert(field_name);
|
|
|
|
|
|
|
|
/* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
|
|
|
|
* the actual counter of it is better rebuild after a reload/reexec. */
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(p, k, *uid_refs) {
|
2020-04-27 08:59:43 +02:00
|
|
|
uint32_t c;
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
uid = PTR_TO_UID(k);
|
|
|
|
c = PTR_TO_UINT32(p);
|
|
|
|
|
|
|
|
if (!(c & DESTROY_IPC_FLAG))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
(void) serialize_item_format(f, field_name, UID_FMT, uid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_serialize_uid_refs(Manager *m, FILE *f) {
|
|
|
|
manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_serialize_gid_refs(Manager *m, FILE *f) {
|
|
|
|
manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
|
|
|
|
}
|
|
|
|
|
2018-10-09 16:45:33 +02:00
|
|
|
int manager_serialize(
|
|
|
|
Manager *m,
|
|
|
|
FILE *f,
|
|
|
|
FDSet *fds,
|
|
|
|
bool switching_root) {
|
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
const char *t;
|
2010-04-21 03:27:44 +02:00
|
|
|
Unit *u;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(f);
|
|
|
|
assert(fds);
|
|
|
|
|
2018-10-13 16:50:04 +02:00
|
|
|
_cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
|
2011-04-20 03:53:12 +02:00
|
|
|
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
|
|
|
|
(void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
|
|
|
|
(void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
|
|
|
|
(void) serialize_bool(f, "taint-usr", m->taint_usr);
|
|
|
|
(void) serialize_bool(f, "ready-sent", m->ready_sent);
|
|
|
|
(void) serialize_bool(f, "taint-logged", m->taint_logged);
|
|
|
|
(void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
|
2011-04-07 18:46:39 +02:00
|
|
|
|
2019-03-15 11:37:43 +01:00
|
|
|
/* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
|
|
|
|
(void) serialize_bool(f, "honor-device-enumeration", !switching_root);
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
if (m->show_status_overridden != _SHOW_STATUS_INVALID)
|
|
|
|
(void) serialize_item(f, "show-status-overridden",
|
|
|
|
show_status_to_string(m->show_status_overridden));
|
2018-07-23 14:55:42 +02:00
|
|
|
|
2018-05-30 17:57:23 +02:00
|
|
|
if (m->log_level_overridden)
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
|
2018-06-01 18:21:03 +02:00
|
|
|
if (m->log_target_overridden)
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
|
2018-05-30 17:57:23 +02:00
|
|
|
|
2020-04-22 16:16:47 +02:00
|
|
|
(void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
|
|
|
|
(void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
|
|
|
|
(void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
|
|
|
|
|
2020-09-04 17:28:53 +02:00
|
|
|
for (ManagerTimestamp q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
|
2018-10-17 20:32:20 +02:00
|
|
|
_cleanup_free_ char *joined = NULL;
|
|
|
|
|
2018-10-17 20:35:28 +02:00
|
|
|
if (!manager_timestamp_shall_serialize(q))
|
2017-11-20 21:01:13 +01:00
|
|
|
continue;
|
2012-05-16 14:22:41 +02:00
|
|
|
|
2018-10-17 20:32:20 +02:00
|
|
|
joined = strjoin(manager_timestamp_to_string(q), "-timestamp");
|
|
|
|
if (!joined)
|
|
|
|
return log_oom();
|
|
|
|
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) serialize_dual_timestamp(f, joined, m->timestamps + q);
|
2012-05-16 14:22:41 +02:00
|
|
|
}
|
2010-10-18 22:39:06 +02:00
|
|
|
|
2017-02-11 03:44:21 +01:00
|
|
|
if (!switching_root)
|
2018-10-31 15:49:19 +01:00
|
|
|
(void) serialize_strv(f, "env", m->client_environment);
|
2013-02-12 00:14:39 +01:00
|
|
|
|
2013-12-21 00:19:37 +01:00
|
|
|
if (m->notify_fd >= 0) {
|
2018-10-17 20:40:09 +02:00
|
|
|
r = serialize_fd(f, fds, "notify-fd", m->notify_fd);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) serialize_item(f, "notify-socket", m->notify_socket);
|
2013-12-21 00:19:37 +01:00
|
|
|
}
|
|
|
|
|
2016-05-04 20:43:23 +02:00
|
|
|
if (m->cgroups_agent_fd >= 0) {
|
2018-10-17 20:40:09 +02:00
|
|
|
r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-05-04 20:43:23 +02:00
|
|
|
}
|
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
if (m->user_lookup_fds[0] >= 0) {
|
|
|
|
int copy0, copy1;
|
|
|
|
|
|
|
|
copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]);
|
2018-10-10 13:33:49 +02:00
|
|
|
if (copy0 < 0)
|
2018-10-17 20:40:09 +02:00
|
|
|
return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m");
|
2016-08-01 19:24:40 +02:00
|
|
|
|
|
|
|
copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]);
|
2018-10-10 13:33:49 +02:00
|
|
|
if (copy1 < 0)
|
2018-10-17 20:40:09 +02:00
|
|
|
return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m");
|
2016-08-01 19:24:40 +02:00
|
|
|
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1);
|
2016-08-01 19:24:40 +02:00
|
|
|
}
|
|
|
|
|
2016-08-15 18:12:01 +02:00
|
|
|
bus_track_serialize(m->subscribed, f, "subscribed");
|
2013-07-10 19:24:03 +02:00
|
|
|
|
2016-07-14 12:37:28 +02:00
|
|
|
r = dynamic_user_serialize(m, f, fds);
|
|
|
|
if (r < 0)
|
2018-10-10 13:33:49 +02:00
|
|
|
return r;
|
2016-07-14 12:37:28 +02:00
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
manager_serialize_uid_refs(m, f);
|
|
|
|
manager_serialize_gid_refs(m, f);
|
|
|
|
|
2018-02-06 08:00:34 +01:00
|
|
|
r = exec_runtime_serialize(m, f, fds);
|
|
|
|
if (r < 0)
|
2018-10-10 13:33:49 +02:00
|
|
|
return r;
|
2018-02-06 08:00:34 +01:00
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
(void) fputc('\n', f);
|
2010-10-20 14:40:44 +02:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(u, t, m->units) {
|
2012-01-15 12:04:08 +01:00
|
|
|
if (u->id != t)
|
2010-04-21 03:27:44 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Start marker */
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs(u->id, f);
|
|
|
|
fputc('\n', f);
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2013-07-10 19:24:03 +02:00
|
|
|
r = unit_serialize(u, f, fds, !switching_root);
|
2018-10-09 16:45:33 +02:00
|
|
|
if (r < 0)
|
2018-10-10 13:33:49 +02:00
|
|
|
return r;
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
2018-06-20 19:38:30 +02:00
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
2018-10-17 20:40:09 +02:00
|
|
|
return log_error_errno(r, "Failed to flush serialization: %m");
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2011-04-28 22:07:01 +02:00
|
|
|
r = bus_fdset_add_all(m, fds);
|
|
|
|
if (r < 0)
|
2018-10-17 20:40:09 +02:00
|
|
|
return log_error_errno(r, "Failed to add bus sockets to serialization: %m");
|
2018-10-09 16:45:33 +02:00
|
|
|
|
2018-10-10 13:33:49 +02:00
|
|
|
return 0;
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
2018-10-30 08:05:02 +01:00
|
|
|
static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, FDSet *fds) {
|
|
|
|
Unit *u;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = manager_load_unit(m, name, NULL, NULL, &u);
|
|
|
|
if (r < 0) {
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return r;
|
|
|
|
return log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = unit_deserialize(u, f, fds);
|
|
|
|
if (r < 0) {
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return r;
|
|
|
|
return log_notice_errno(r, "Failed to deserialize unit \"%s\", skipping: %m", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
|
|
|
|
const char *unit_name;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
for (;;) {
|
2018-12-23 15:01:03 +01:00
|
|
|
_cleanup_free_ char *line = NULL;
|
2018-10-30 08:05:02 +01:00
|
|
|
/* Start marker */
|
|
|
|
r = read_line(f, LONG_LINE_MAX, &line);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to read serialization line: %m");
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
unit_name = strstrip(line);
|
|
|
|
|
|
|
|
r = manager_deserialize_one_unit(m, unit_name, f, fds);
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return r;
|
|
|
|
if (r < 0) {
|
|
|
|
r = unit_deserialize_skip(f);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-22 16:16:47 +02:00
|
|
|
usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_USER(m))
|
|
|
|
return USEC_INFINITY;
|
|
|
|
|
|
|
|
if (timestamp_is_set(m->watchdog_overridden[t]))
|
|
|
|
return m->watchdog_overridden[t];
|
|
|
|
|
|
|
|
return m->watchdog[t];
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_USER(m))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m->watchdog[t] == timeout)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (t == WATCHDOG_RUNTIME)
|
|
|
|
if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
|
|
|
|
if (timestamp_is_set(timeout))
|
|
|
|
r = watchdog_set_timeout(&timeout);
|
|
|
|
else
|
|
|
|
watchdog_close(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r >= 0)
|
|
|
|
m->watchdog[t] = timeout;
|
|
|
|
}
|
|
|
|
|
2020-06-04 13:25:25 +02:00
|
|
|
int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
|
2020-04-22 16:16:47 +02:00
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_USER(m))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (m->watchdog_overridden[t] == timeout)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (t == WATCHDOG_RUNTIME) {
|
|
|
|
usec_t *p;
|
|
|
|
|
|
|
|
p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
|
|
|
|
if (timestamp_is_set(*p))
|
|
|
|
r = watchdog_set_timeout(p);
|
|
|
|
else
|
|
|
|
watchdog_close(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r >= 0)
|
|
|
|
m->watchdog_overridden[t] = timeout;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-27 09:01:18 +02:00
|
|
|
static void manager_deserialize_uid_refs_one_internal(
|
|
|
|
Manager *m,
|
|
|
|
Hashmap** uid_refs,
|
|
|
|
const char *value) {
|
|
|
|
|
|
|
|
uid_t uid;
|
|
|
|
uint32_t c;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(uid_refs);
|
|
|
|
assert(value);
|
|
|
|
|
|
|
|
r = parse_uid(value, &uid);
|
|
|
|
if (r < 0 || uid == 0) {
|
|
|
|
log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
|
|
|
|
if (r < 0) {
|
|
|
|
log_oom();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
|
|
|
|
if (c & DESTROY_IPC_FLAG)
|
|
|
|
return;
|
|
|
|
|
|
|
|
c |= DESTROY_IPC_FLAG;
|
|
|
|
|
|
|
|
r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
|
|
|
|
if (r < 0) {
|
|
|
|
log_debug_errno(r, "Failed to add UID reference entry: %m");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
|
|
|
|
manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
|
|
|
|
manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
|
|
|
|
}
|
|
|
|
|
2010-04-21 03:27:44 +02:00
|
|
|
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(f);
|
|
|
|
|
|
|
|
log_debug("Deserializing state...");
|
|
|
|
|
2018-10-09 16:59:16 +02:00
|
|
|
/* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
|
|
|
|
* increased it to non-zero, which is why we just increase it by one here and down again at the end of this
|
|
|
|
* call. */
|
2018-10-13 16:50:04 +02:00
|
|
|
_cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
|
2010-07-10 04:51:03 +02:00
|
|
|
|
2010-08-11 20:19:27 +02:00
|
|
|
for (;;) {
|
2018-10-17 18:36:24 +02:00
|
|
|
_cleanup_free_ char *line = NULL;
|
2017-06-24 01:20:54 +02:00
|
|
|
const char *val, *l;
|
2010-08-11 20:19:27 +02:00
|
|
|
|
2018-10-17 18:36:24 +02:00
|
|
|
r = read_line(f, LONG_LINE_MAX, &line);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to read serialization line: %m");
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
2010-08-11 20:19:27 +02:00
|
|
|
|
|
|
|
l = strstrip(line);
|
2018-10-17 18:36:24 +02:00
|
|
|
if (isempty(l)) /* end marker */
|
2010-08-11 20:19:27 +02:00
|
|
|
break;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if ((val = startswith(l, "current-job-id="))) {
|
2011-04-07 18:46:39 +02:00
|
|
|
uint32_t id;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if (safe_atou32(val, &id) < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse current job id value '%s', ignoring.", val);
|
2011-04-07 18:46:39 +02:00
|
|
|
else
|
|
|
|
m->current_job_id = MAX(m->current_job_id, id);
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "n-installed-jobs="))) {
|
2012-06-29 19:47:38 +02:00
|
|
|
uint32_t n;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if (safe_atou32(val, &n) < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse installed jobs counter '%s', ignoring.", val);
|
2012-06-29 19:47:38 +02:00
|
|
|
else
|
|
|
|
m->n_installed_jobs += n;
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "n-failed-jobs="))) {
|
2012-06-29 19:47:38 +02:00
|
|
|
uint32_t n;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if (safe_atou32(val, &n) < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse failed jobs counter '%s', ignoring.", val);
|
2012-06-29 19:47:38 +02:00
|
|
|
else
|
|
|
|
m->n_failed_jobs += n;
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "taint-usr="))) {
|
2011-04-07 18:46:39 +02:00
|
|
|
int b;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
b = parse_boolean(val);
|
2013-11-30 03:53:42 +01:00
|
|
|
if (b < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse taint /usr flag '%s', ignoring.", val);
|
2011-04-07 18:46:39 +02:00
|
|
|
else
|
|
|
|
m->taint_usr = m->taint_usr || b;
|
2013-11-19 21:12:59 +01:00
|
|
|
|
2017-10-24 14:48:54 +02:00
|
|
|
} else if ((val = startswith(l, "ready-sent="))) {
|
|
|
|
int b;
|
|
|
|
|
|
|
|
b = parse_boolean(val);
|
|
|
|
if (b < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse ready-sent flag '%s', ignoring.", val);
|
2017-10-24 14:48:54 +02:00
|
|
|
else
|
|
|
|
m->ready_sent = m->ready_sent || b;
|
|
|
|
|
2018-01-21 13:17:54 +01:00
|
|
|
} else if ((val = startswith(l, "taint-logged="))) {
|
|
|
|
int b;
|
|
|
|
|
|
|
|
b = parse_boolean(val);
|
|
|
|
if (b < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse taint-logged flag '%s', ignoring.", val);
|
2018-01-21 13:17:54 +01:00
|
|
|
else
|
|
|
|
m->taint_logged = m->taint_logged || b;
|
|
|
|
|
2017-03-20 13:10:43 +01:00
|
|
|
} else if ((val = startswith(l, "service-watchdogs="))) {
|
|
|
|
int b;
|
|
|
|
|
|
|
|
b = parse_boolean(val);
|
|
|
|
if (b < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val);
|
2017-03-20 13:10:43 +01:00
|
|
|
else
|
|
|
|
m->service_watchdogs = b;
|
|
|
|
|
2019-03-15 11:37:43 +01:00
|
|
|
} else if ((val = startswith(l, "honor-device-enumeration="))) {
|
|
|
|
int b;
|
|
|
|
|
|
|
|
b = parse_boolean(val);
|
|
|
|
if (b < 0)
|
|
|
|
log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
|
|
|
|
else
|
|
|
|
m->honor_device_enumeration = b;
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
} else if ((val = startswith(l, "show-status-overridden="))) {
|
2018-07-23 14:55:42 +02:00
|
|
|
ShowStatus s;
|
|
|
|
|
|
|
|
s = show_status_from_string(val);
|
|
|
|
if (s < 0)
|
2020-04-27 11:06:34 +02:00
|
|
|
log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
|
2018-07-23 14:55:42 +02:00
|
|
|
else
|
2020-06-04 13:25:25 +02:00
|
|
|
manager_override_show_status(m, s, "deserialize");
|
2018-07-23 14:55:42 +02:00
|
|
|
|
2018-05-30 17:57:23 +02:00
|
|
|
} else if ((val = startswith(l, "log-level-override="))) {
|
|
|
|
int level;
|
|
|
|
|
|
|
|
level = log_level_from_string(val);
|
|
|
|
if (level < 0)
|
|
|
|
log_notice("Failed to parse log-level-override value '%s', ignoring.", val);
|
|
|
|
else
|
|
|
|
manager_override_log_level(m, level);
|
|
|
|
|
2018-06-01 18:21:03 +02:00
|
|
|
} else if ((val = startswith(l, "log-target-override="))) {
|
|
|
|
LogTarget target;
|
|
|
|
|
|
|
|
target = log_target_from_string(val);
|
|
|
|
if (target < 0)
|
|
|
|
log_notice("Failed to parse log-target-override value '%s', ignoring.", val);
|
|
|
|
else
|
|
|
|
manager_override_log_target(m, target);
|
|
|
|
|
2020-04-22 16:16:47 +02:00
|
|
|
} else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
|
|
|
|
usec_t t;
|
|
|
|
|
|
|
|
if (deserialize_usec(val, &t) < 0)
|
|
|
|
log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
|
|
|
|
else
|
2020-06-04 13:25:25 +02:00
|
|
|
manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
|
2020-04-22 16:16:47 +02:00
|
|
|
|
|
|
|
} else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
|
|
|
|
usec_t t;
|
|
|
|
|
|
|
|
if (deserialize_usec(val, &t) < 0)
|
|
|
|
log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
|
|
|
|
else
|
2020-06-04 13:25:25 +02:00
|
|
|
manager_override_watchdog(m, WATCHDOG_REBOOT, t);
|
2020-04-22 16:16:47 +02:00
|
|
|
|
|
|
|
} else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
|
|
|
|
usec_t t;
|
|
|
|
|
|
|
|
if (deserialize_usec(val, &t) < 0)
|
|
|
|
log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
|
|
|
|
else
|
2020-06-04 13:25:25 +02:00
|
|
|
manager_override_watchdog(m, WATCHDOG_KEXEC, t);
|
2020-04-22 16:16:47 +02:00
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
} else if (startswith(l, "env=")) {
|
2018-10-31 15:49:19 +01:00
|
|
|
r = deserialize_environment(l + 4, &m->client_environment);
|
2015-04-06 20:11:41 +02:00
|
|
|
if (r < 0)
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l);
|
2013-11-30 03:53:42 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "notify-fd="))) {
|
2013-12-21 00:19:37 +01:00
|
|
|
int fd;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse notify fd, ignoring: \"%s\"", val);
|
2013-12-21 00:19:37 +01:00
|
|
|
else {
|
2014-03-18 19:22:43 +01:00
|
|
|
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
|
|
|
|
safe_close(m->notify_fd);
|
2013-12-21 00:19:37 +01:00
|
|
|
m->notify_fd = fdset_remove(fds, fd);
|
|
|
|
}
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "notify-socket="))) {
|
2018-10-10 13:54:13 +02:00
|
|
|
r = free_and_strdup(&m->notify_socket, val);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-12-21 00:19:37 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "cgroups-agent-fd="))) {
|
2016-05-04 20:43:23 +02:00
|
|
|
int fd;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if (safe_atoi(val, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse cgroups agent fd, ignoring.: %s", val);
|
2016-05-04 20:43:23 +02:00
|
|
|
else {
|
|
|
|
m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
|
|
|
|
safe_close(m->cgroups_agent_fd);
|
|
|
|
m->cgroups_agent_fd = fdset_remove(fds, fd);
|
|
|
|
}
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "user-lookup="))) {
|
2016-08-01 19:24:40 +02:00
|
|
|
int fd0, fd1;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if (sscanf(val, "%i %i", &fd0, &fd1) != 2 || fd0 < 0 || fd1 < 0 || fd0 == fd1 || !fdset_contains(fds, fd0) || !fdset_contains(fds, fd1))
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Failed to parse user lookup fd, ignoring: %s", val);
|
2016-08-01 19:24:40 +02:00
|
|
|
else {
|
|
|
|
m->user_lookup_event_source = sd_event_source_unref(m->user_lookup_event_source);
|
|
|
|
safe_close_pair(m->user_lookup_fds);
|
|
|
|
m->user_lookup_fds[0] = fdset_remove(fds, fd0);
|
|
|
|
m->user_lookup_fds[1] = fdset_remove(fds, fd1);
|
|
|
|
}
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(l, "dynamic-user=")))
|
|
|
|
dynamic_user_deserialize_one(m, val, fds);
|
|
|
|
else if ((val = startswith(l, "destroy-ipc-uid=")))
|
|
|
|
manager_deserialize_uid_refs_one(m, val);
|
|
|
|
else if ((val = startswith(l, "destroy-ipc-gid=")))
|
|
|
|
manager_deserialize_gid_refs_one(m, val);
|
2018-02-06 08:00:34 +01:00
|
|
|
else if ((val = startswith(l, "exec-runtime=")))
|
2020-06-28 19:54:49 +02:00
|
|
|
(void) exec_runtime_deserialize_one(m, val, fds);
|
2016-10-22 22:11:41 +02:00
|
|
|
else if ((val = startswith(l, "subscribed="))) {
|
2016-08-15 18:12:01 +02:00
|
|
|
|
2018-10-10 13:54:13 +02:00
|
|
|
if (strv_extend(&m->deserialized_subscribed, val) < 0)
|
|
|
|
return -ENOMEM;
|
2018-10-09 16:54:40 +02:00
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
} else {
|
|
|
|
ManagerTimestamp q;
|
|
|
|
|
|
|
|
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
|
|
|
|
val = startswith(l, manager_timestamp_to_string(q));
|
|
|
|
if (!val)
|
|
|
|
continue;
|
2016-08-15 18:12:01 +02:00
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
val = startswith(val, "-timestamp=");
|
|
|
|
if (val)
|
|
|
|
break;
|
|
|
|
}
|
2016-08-15 18:12:01 +02:00
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
|
2018-10-17 20:40:09 +02:00
|
|
|
(void) deserialize_dual_timestamp(val, m->timestamps + q);
|
2017-11-20 21:01:13 +01:00
|
|
|
else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */
|
2018-10-09 16:53:35 +02:00
|
|
|
log_notice("Unknown serialization item '%s', ignoring.", l);
|
2017-11-20 21:01:13 +01:00
|
|
|
}
|
2010-08-11 20:19:27 +02:00
|
|
|
}
|
|
|
|
|
2018-10-30 08:05:02 +01:00
|
|
|
return manager_deserialize_units(m, f, fds);
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int manager_reload(Manager *m) {
|
2018-10-10 13:33:49 +02:00
|
|
|
_cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
|
2013-10-12 01:33:48 +02:00
|
|
|
_cleanup_fdset_free_ FDSet *fds = NULL;
|
2018-10-09 17:02:14 +02:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
int r;
|
2010-04-21 03:27:44 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
r = manager_open_serialization(m, &f);
|
|
|
|
if (r < 0)
|
2018-10-09 17:02:14 +02:00
|
|
|
return log_error_errno(r, "Failed to create serialization file: %m");
|
2011-04-20 03:53:12 +02:00
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
fds = fdset_new();
|
2018-10-09 17:02:14 +02:00
|
|
|
if (!fds)
|
|
|
|
return log_oom();
|
|
|
|
|
2018-10-10 13:33:49 +02:00
|
|
|
/* We are officially in reload mode from here on. */
|
|
|
|
reloading = manager_reloading_start(m);
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2013-04-08 14:05:24 +02:00
|
|
|
r = manager_serialize(m, f, fds, false);
|
2018-10-10 13:33:49 +02:00
|
|
|
if (r < 0)
|
2018-10-17 20:40:09 +02:00
|
|
|
return r;
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2018-10-10 13:33:49 +02:00
|
|
|
if (fseeko(f, 0, SEEK_SET) < 0)
|
|
|
|
return log_error_errno(errno, "Failed to seek to beginning of serialization: %m");
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2018-10-09 17:02:14 +02:00
|
|
|
/* 💀 This is the point of no return, from here on there is no way back. 💀 */
|
2018-10-10 13:33:49 +02:00
|
|
|
reloading = NULL;
|
2018-10-09 17:02:14 +02:00
|
|
|
|
|
|
|
bus_manager_send_reloading(m, true);
|
|
|
|
|
|
|
|
/* Start by flushing out all jobs and units, all generated units, all runtime environments, all dynamic users
|
|
|
|
* and everything else that is worth flushing out. We'll get it all back from the serialization — if we need
|
|
|
|
* it.*/
|
|
|
|
|
2010-04-21 03:27:44 +02:00
|
|
|
manager_clear_jobs_and_units(m);
|
2016-04-06 20:47:44 +02:00
|
|
|
lookup_paths_flush_generator(&m->lookup_paths);
|
2010-06-15 14:45:15 +02:00
|
|
|
lookup_paths_free(&m->lookup_paths);
|
2018-02-06 08:00:34 +01:00
|
|
|
exec_runtime_vacuum(m);
|
2016-07-14 12:37:28 +02:00
|
|
|
dynamic_user_vacuum(m, false);
|
2016-08-01 19:24:40 +02:00
|
|
|
m->uid_refs = hashmap_free(m->uid_refs);
|
|
|
|
m->gid_refs = hashmap_free(m->gid_refs);
|
2010-06-15 14:32:26 +02:00
|
|
|
|
2018-10-02 12:35:37 +02:00
|
|
|
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
|
2018-10-09 17:02:14 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to initialize path lookup table, ignoring: %m");
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2018-10-09 17:02:14 +02:00
|
|
|
(void) manager_run_environment_generators(m);
|
|
|
|
(void) manager_run_generators(m);
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
|
core: stop removing non-existent and duplicate lookup paths
When we would iterate over the lookup paths for each unit, making the list as
short as possible was important for performance. With the current cache, it
doesn't matter much. Two classes of paths were being removed:
- paths which don't exist in the filesystem
- paths which symlink to a path earlier in the search list
Both of those points cause problems with the caching code:
- if a user creates a directory that didn't exist before and puts units there,
now we will notice the new mtime an properly load the unit. When the path
was removed from list, we wouldn't.
- we now properly detect whether a unit path is on the path or not.
Before, if e.g. /lib/systemd/system, /usr/lib/systemd/systemd were both on
the path, and /lib was a symlink to /usr/lib, the second directory would be
pruned from the path. Then, the code would think that a symlink
/etc/systemd/system/foo.service→/lib/systemd/system/foo.service is an alias,
but /etc/systemd/system/foo.service→/usr/lib/systemd/system/foo.service would
be considered a link (in the systemctl link sense).
Removing the pruning has a slight negative performance impact in case of
usr-merge systems which have systemd compiled with non-usr-merge paths.
Non-usr-merge systems are deprecated, and this impact should be very small, so
I think it's OK. If it turns out to be an issue, the loop in function that
builds the cache could be improved to skip over "duplicate" directories with
same logic that the cache pruning did before. I didn't want to add this,
becuase it complicates the code to improve a corner case.
Fixes #13272.
2019-08-26 08:58:41 +02:00
|
|
|
lookup_paths_log(&m->lookup_paths);
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2019-07-10 18:01:13 +02:00
|
|
|
/* We flushed out generated files, for which we don't watch mtime, so we should flush the old map. */
|
2019-07-18 13:11:28 +02:00
|
|
|
manager_free_unit_name_maps(m);
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2018-10-09 17:02:14 +02:00
|
|
|
/* First, enumerate what we can from kernel and suchlike */
|
2018-10-09 17:37:57 +02:00
|
|
|
manager_enumerate_perpetual(m);
|
2015-11-10 20:36:37 +01:00
|
|
|
manager_enumerate(m);
|
2010-04-21 03:27:44 +02:00
|
|
|
|
|
|
|
/* Second, deserialize our stored data */
|
2018-10-09 17:02:14 +02:00
|
|
|
r = manager_deserialize(m, f, fds);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Deserialization failed, proceeding anyway: %m");
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2018-10-09 17:02:14 +02:00
|
|
|
/* We don't need the serialization anymore */
|
2018-06-04 23:05:39 +02:00
|
|
|
f = safe_fclose(f);
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2018-10-09 17:02:14 +02:00
|
|
|
/* Re-register notify_fd as event source, and set up other sockets/communication channels we might need */
|
|
|
|
(void) manager_setup_notify(m);
|
|
|
|
(void) manager_setup_cgroups_agent(m);
|
|
|
|
(void) manager_setup_user_lookup_fd(m);
|
2016-08-01 19:24:40 +02:00
|
|
|
|
2010-04-21 03:27:44 +02:00
|
|
|
/* Third, fire things up! */
|
2015-04-24 16:09:15 +02:00
|
|
|
manager_coldplug(m);
|
2010-04-21 03:27:44 +02:00
|
|
|
|
2018-10-09 19:34:23 +02:00
|
|
|
/* Clean up runtime objects no longer referenced */
|
|
|
|
manager_vacuum(m);
|
2018-02-06 08:00:34 +01:00
|
|
|
|
2018-10-09 17:02:14 +02:00
|
|
|
/* Consider the reload process complete now. */
|
2018-03-21 12:03:45 +01:00
|
|
|
assert(m->n_reloading > 0);
|
|
|
|
m->n_reloading--;
|
|
|
|
|
2019-03-15 11:37:43 +01:00
|
|
|
/* On manager reloading, device tag data should exists, thus, we should honor the results of device
|
|
|
|
* enumeration. The flag should be always set correctly by the serialized data, but it may fail. So,
|
|
|
|
* let's always set the flag here for safety. */
|
|
|
|
m->honor_device_enumeration = true;
|
|
|
|
|
2018-10-09 19:41:24 +02:00
|
|
|
manager_ready(m);
|
2015-12-22 11:37:09 +01:00
|
|
|
|
2013-07-10 21:10:53 +02:00
|
|
|
m->send_reloading_done = true;
|
2018-10-09 17:02:14 +02:00
|
|
|
return 0;
|
2010-04-21 03:27:44 +02:00
|
|
|
}
|
|
|
|
|
2010-08-31 00:23:34 +02:00
|
|
|
void manager_reset_failed(Manager *m) {
|
2010-07-18 04:58:01 +02:00
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(u, m->units)
|
2010-08-31 00:23:34 +02:00
|
|
|
unit_reset_failed(u);
|
2010-07-18 04:58:01 +02:00
|
|
|
}
|
|
|
|
|
2013-04-26 02:57:41 +02:00
|
|
|
bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
|
2010-09-01 03:30:59 +02:00
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
/* Returns true if the unit is inactive or going down */
|
2013-01-02 22:03:35 +01:00
|
|
|
u = manager_get_unit(m, name);
|
|
|
|
if (!u)
|
2010-09-01 03:30:59 +02:00
|
|
|
return true;
|
|
|
|
|
2013-04-26 02:57:41 +02:00
|
|
|
return unit_inactive_or_pending(u);
|
2010-09-01 03:30:59 +02:00
|
|
|
}
|
|
|
|
|
2018-01-21 13:17:54 +01:00
|
|
|
static void log_taint_string(Manager *m) {
|
|
|
|
_cleanup_free_ char *taint = NULL;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_USER(m) || m->taint_logged)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m->taint_logged = true; /* only check for taint once */
|
|
|
|
|
|
|
|
taint = manager_taint_string(m);
|
|
|
|
if (isempty(taint))
|
|
|
|
return;
|
|
|
|
|
|
|
|
log_struct(LOG_NOTICE,
|
|
|
|
LOG_MESSAGE("System is tainted: %s", taint),
|
|
|
|
"TAINT=%s", taint,
|
2018-06-04 12:59:22 +02:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_TAINTED_STR);
|
2018-01-21 13:17:54 +01:00
|
|
|
}
|
|
|
|
|
2014-11-02 18:19:38 +01:00
|
|
|
static void manager_notify_finished(Manager *m) {
|
2012-09-13 19:29:46 +02:00
|
|
|
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
|
2012-09-13 18:54:32 +02:00
|
|
|
usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
|
2010-09-21 04:14:38 +02:00
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2010-09-21 04:14:38 +02:00
|
|
|
return;
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
|
2017-12-25 05:08:23 +01:00
|
|
|
char ts[FORMAT_TIMESPAN_MAX];
|
2018-01-20 01:06:34 +01:00
|
|
|
char buf[FORMAT_TIMESPAN_MAX + STRLEN(" (firmware) + ") + FORMAT_TIMESPAN_MAX + STRLEN(" (loader) + ")]
|
|
|
|
= {};
|
|
|
|
char *p = buf;
|
|
|
|
size_t size = sizeof buf;
|
2011-03-14 21:47:41 +01:00
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
/* Note that MANAGER_TIMESTAMP_KERNEL's monotonic value is always at 0, and
|
|
|
|
* MANAGER_TIMESTAMP_FIRMWARE's and MANAGER_TIMESTAMP_LOADER's monotonic value should be considered
|
2012-09-13 18:54:32 +02:00
|
|
|
* negative values. */
|
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
firmware_usec = m->timestamps[MANAGER_TIMESTAMP_FIRMWARE].monotonic - m->timestamps[MANAGER_TIMESTAMP_LOADER].monotonic;
|
|
|
|
loader_usec = m->timestamps[MANAGER_TIMESTAMP_LOADER].monotonic - m->timestamps[MANAGER_TIMESTAMP_KERNEL].monotonic;
|
|
|
|
userspace_usec = m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic - m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
|
|
|
|
total_usec = m->timestamps[MANAGER_TIMESTAMP_FIRMWARE].monotonic + m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic;
|
2011-06-27 13:47:03 +02:00
|
|
|
|
2017-12-25 05:08:23 +01:00
|
|
|
if (firmware_usec > 0)
|
|
|
|
size = strpcpyf(&p, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), firmware_usec, USEC_PER_MSEC));
|
|
|
|
if (loader_usec > 0)
|
|
|
|
size = strpcpyf(&p, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), loader_usec, USEC_PER_MSEC));
|
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
if (dual_timestamp_is_set(&m->timestamps[MANAGER_TIMESTAMP_INITRD])) {
|
2011-06-27 13:47:03 +02:00
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
/* The initrd case on bare-metal*/
|
|
|
|
kernel_usec = m->timestamps[MANAGER_TIMESTAMP_INITRD].monotonic - m->timestamps[MANAGER_TIMESTAMP_KERNEL].monotonic;
|
|
|
|
initrd_usec = m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic - m->timestamps[MANAGER_TIMESTAMP_INITRD].monotonic;
|
2011-06-27 13:47:03 +02:00
|
|
|
|
2014-08-22 16:41:00 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
|
2014-08-22 16:41:00 +02:00
|
|
|
"KERNEL_USEC="USEC_FMT, kernel_usec,
|
|
|
|
"INITRD_USEC="USEC_FMT, initrd_usec,
|
|
|
|
"USERSPACE_USEC="USEC_FMT, userspace_usec,
|
2017-12-25 05:08:23 +01:00
|
|
|
LOG_MESSAGE("Startup finished in %s%s (kernel) + %s (initrd) + %s (userspace) = %s.",
|
|
|
|
buf,
|
2014-11-28 02:05:14 +01:00
|
|
|
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),
|
2018-06-04 12:59:22 +02:00
|
|
|
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
|
2011-06-27 13:47:03 +02:00
|
|
|
} else {
|
2017-11-20 21:01:13 +01:00
|
|
|
/* The initrd-less case on bare-metal*/
|
|
|
|
|
|
|
|
kernel_usec = m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic - m->timestamps[MANAGER_TIMESTAMP_KERNEL].monotonic;
|
2011-06-27 13:47:03 +02:00
|
|
|
initrd_usec = 0;
|
|
|
|
|
2012-08-24 22:43:33 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
|
2014-08-22 16:41:00 +02:00
|
|
|
"KERNEL_USEC="USEC_FMT, kernel_usec,
|
2013-12-30 23:22:26 +01:00
|
|
|
"USERSPACE_USEC="USEC_FMT, userspace_usec,
|
2017-12-25 05:08:23 +01:00
|
|
|
LOG_MESSAGE("Startup finished in %s%s (kernel) + %s (userspace) = %s.",
|
|
|
|
buf,
|
2014-11-28 02:05:14 +01:00
|
|
|
format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
|
|
|
|
format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
|
2018-06-04 12:59:22 +02:00
|
|
|
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
|
2014-08-22 16:41:00 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-01-23 16:32:06 +01:00
|
|
|
/* The container and --user case */
|
2014-08-22 16:41:00 +02:00
|
|
|
firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
|
2017-11-20 21:01:13 +01:00
|
|
|
total_usec = userspace_usec = m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic - m->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic;
|
2014-08-22 16:41:00 +02:00
|
|
|
|
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_USER_STARTUP_FINISHED_STR,
|
2014-08-22 16:41:00 +02:00
|
|
|
"USERSPACE_USEC="USEC_FMT, userspace_usec,
|
2014-11-28 02:05:14 +01:00
|
|
|
LOG_MESSAGE("Startup finished in %s.",
|
2018-06-04 12:59:22 +02:00
|
|
|
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)));
|
2011-06-27 13:47:03 +02:00
|
|
|
}
|
2010-09-21 04:14:38 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
|
2011-06-30 02:15:41 +02:00
|
|
|
|
|
|
|
sd_notifyf(false,
|
2017-10-24 14:48:54 +02:00
|
|
|
m->ready_sent ? "STATUS=Startup finished in %s."
|
|
|
|
: "READY=1\n"
|
|
|
|
"STATUS=Startup finished in %s.",
|
2013-04-04 02:56:56 +02:00
|
|
|
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
|
2017-10-24 14:48:54 +02:00
|
|
|
m->ready_sent = true;
|
2018-01-21 13:17:54 +01:00
|
|
|
|
|
|
|
log_taint_string(m);
|
2010-09-21 04:14:38 +02:00
|
|
|
}
|
|
|
|
|
2018-01-23 16:32:06 +01:00
|
|
|
static void manager_send_ready(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* We send READY=1 on reaching basic.target only when running in --user mode. */
|
|
|
|
if (!MANAGER_IS_USER(m) || m->ready_sent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m->ready_sent = true;
|
|
|
|
|
|
|
|
sd_notifyf(false,
|
|
|
|
"READY=1\n"
|
|
|
|
"STATUS=Reached " SPECIAL_BASIC_TARGET ".");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_check_basic_target(Manager *m) {
|
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Small shortcut */
|
|
|
|
if (m->ready_sent && m->taint_logged)
|
|
|
|
return;
|
|
|
|
|
|
|
|
u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
|
|
|
|
if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* For user managers, send out READY=1 as soon as we reach basic.target */
|
|
|
|
manager_send_ready(m);
|
|
|
|
|
|
|
|
/* Log the taint string as soon as we reach basic.target */
|
|
|
|
log_taint_string(m);
|
|
|
|
}
|
|
|
|
|
2014-11-02 18:19:38 +01:00
|
|
|
void manager_check_finished(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
2016-02-24 21:36:09 +01:00
|
|
|
if (MANAGER_IS_RELOADING(m))
|
2015-05-19 19:09:03 +02:00
|
|
|
return;
|
|
|
|
|
2018-01-23 16:43:56 +01:00
|
|
|
/* Verify that we have entered the event loop already, and not left it again. */
|
|
|
|
if (!MANAGER_IS_RUNNING(m))
|
2015-05-21 21:34:36 +02:00
|
|
|
return;
|
|
|
|
|
2018-01-23 16:32:06 +01:00
|
|
|
manager_check_basic_target(m);
|
2017-10-24 14:48:54 +02:00
|
|
|
|
2014-11-02 18:19:38 +01:00
|
|
|
if (hashmap_size(m->jobs) > 0) {
|
|
|
|
if (m->jobs_in_progress_event_source)
|
2015-03-14 03:11:09 +01:00
|
|
|
/* Ignore any failure, this is only for feedback */
|
2020-02-29 16:29:42 +01:00
|
|
|
(void) sd_event_source_set_time(m->jobs_in_progress_event_source,
|
|
|
|
manager_watch_jobs_next_time(m));
|
2014-11-02 18:19:38 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-28 18:39:27 +02:00
|
|
|
/* The jobs hashmap tends to grow a lot during boot, and then it's not reused until shutdown. Let's
|
|
|
|
kill the hashmap if it is relatively large. */
|
|
|
|
if (hashmap_buckets(m->jobs) > hashmap_size(m->units) / 10)
|
|
|
|
m->jobs = hashmap_free(m->jobs);
|
|
|
|
|
2020-02-29 10:59:27 +01:00
|
|
|
manager_flip_auto_status(m, false, "boot finished");
|
2014-11-02 18:19:38 +01:00
|
|
|
|
|
|
|
/* Notify Type=idle units that we are done now */
|
|
|
|
manager_close_idle_pipe(m);
|
|
|
|
|
|
|
|
/* Turn off confirm spawn now */
|
2016-11-02 10:38:22 +01:00
|
|
|
m->confirm_spawn = NULL;
|
2014-11-02 18:19:38 +01:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2017-11-20 21:24:59 +01:00
|
|
|
if (MANAGER_IS_FINISHED(m))
|
2014-11-02 18:19:38 +01:00
|
|
|
return;
|
|
|
|
|
2017-11-20 21:01:13 +01:00
|
|
|
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_FINISH);
|
2014-11-02 18:19:38 +01:00
|
|
|
|
|
|
|
manager_notify_finished(m);
|
|
|
|
|
2015-09-11 18:21:53 +02:00
|
|
|
manager_invalidate_startup_units(m);
|
2014-11-02 18:19:38 +01:00
|
|
|
}
|
|
|
|
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
static bool generator_path_any(const char* const* paths) {
|
|
|
|
char **path;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
/* Optimize by skipping the whole process by not creating output directories
|
|
|
|
* if no generators are found. */
|
|
|
|
STRV_FOREACH(path, (char**) paths)
|
|
|
|
if (access(*path, F_OK) == 0)
|
|
|
|
found = true;
|
|
|
|
else if (errno != ENOENT)
|
|
|
|
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_run_environment_generators(Manager *m) {
|
|
|
|
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
|
2020-02-14 22:43:38 +01:00
|
|
|
_cleanup_strv_free_ char **paths = NULL;
|
2018-10-31 15:49:19 +01:00
|
|
|
void* args[] = {
|
|
|
|
[STDOUT_GENERATE] = &tmp,
|
|
|
|
[STDOUT_COLLECT] = &tmp,
|
|
|
|
[STDOUT_CONSUME] = &m->transient_environment,
|
|
|
|
};
|
2018-11-20 19:14:24 +01:00
|
|
|
int r;
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m) && !(m->test_run_flags & MANAGER_TEST_RUN_ENV_GENERATORS))
|
2017-09-16 11:19:43 +02:00
|
|
|
return 0;
|
|
|
|
|
2020-02-14 22:43:38 +01:00
|
|
|
paths = env_generator_binary_paths(MANAGER_IS_SYSTEM(m));
|
|
|
|
if (!paths)
|
|
|
|
return log_oom();
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
|
2020-02-14 22:43:38 +01:00
|
|
|
if (!generator_path_any((const char* const*) paths))
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-11-20 19:14:24 +01:00
|
|
|
RUN_WITH_UMASK(0022)
|
2020-02-14 22:43:38 +01:00
|
|
|
r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment,
|
2018-09-09 03:18:45 +02:00
|
|
|
args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
|
2018-11-20 19:14:24 +01:00
|
|
|
return r;
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
}
|
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
static int manager_run_generators(Manager *m) {
|
2015-05-12 04:30:38 +02:00
|
|
|
_cleanup_strv_free_ char **paths = NULL;
|
2012-05-23 03:43:29 +02:00
|
|
|
const char *argv[5];
|
|
|
|
int r;
|
2010-11-11 21:28:33 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m) && !(m->test_run_flags & MANAGER_TEST_RUN_GENERATORS))
|
2017-09-16 11:19:43 +02:00
|
|
|
return 0;
|
|
|
|
|
2016-04-06 20:48:58 +02:00
|
|
|
paths = generator_binary_paths(m->unit_file_scope);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
if (!paths)
|
|
|
|
return log_oom();
|
2010-11-11 21:28:33 +01:00
|
|
|
|
manager: run environment generators
Environment file generators are a lot like unit file generators, but not
exactly:
1. environment file generators are run for each manager instance, and their
output is (or at least can be) individualized.
The generators themselves are system-wide, the same for all users.
2. environment file generators are run sequentially, in priority order.
Thus, the lifetime of those files is tied to lifecycle of the manager
instance. Because generators are run sequentially, later generators can use or
modify the output of earlier generators.
Each generator is run with no arguments, and the whole state is stored in the
environment variables. The generator can echo a set of variable assignments to
standard output:
VAR_A=something
VAR_B=something else
This output is parsed, and the next and subsequent generators run with those
updated variables in the environment. After the last generator is done, the
environment that the manager itself exports is updated.
Each generator must return 0, otherwise the output is ignored.
The generators in */user-env-generator are for the user session managers,
including root, and the ones in */system-env-generator are for pid1.
2017-01-22 07:13:47 +01:00
|
|
|
if (!generator_path_any((const char* const*) paths))
|
|
|
|
return 0;
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2016-02-25 01:44:30 +01:00
|
|
|
r = lookup_paths_mkdir_generator(&m->lookup_paths);
|
2018-10-09 16:47:30 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to create generator directories: %m");
|
2012-05-23 03:43:29 +02:00
|
|
|
goto finish;
|
2018-10-09 16:47:30 +02:00
|
|
|
}
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2011-02-15 00:30:11 +01:00
|
|
|
argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
|
2016-02-24 15:31:33 +01:00
|
|
|
argv[1] = m->lookup_paths.generator;
|
|
|
|
argv[2] = m->lookup_paths.generator_early;
|
|
|
|
argv[3] = m->lookup_paths.generator_late;
|
2012-05-23 03:43:29 +02:00
|
|
|
argv[4] = NULL;
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
RUN_WITH_UMASK(0022)
|
2018-09-09 03:18:45 +02:00
|
|
|
(void) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, NULL, NULL,
|
|
|
|
(char**) argv, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
|
2018-10-09 16:47:30 +02:00
|
|
|
|
|
|
|
r = 0;
|
2010-11-11 21:28:33 +01:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
finish:
|
2016-02-25 01:44:30 +01:00
|
|
|
lookup_paths_trim_generator(&m->lookup_paths);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return r;
|
2010-11-11 21:28:33 +01:00
|
|
|
}
|
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
int manager_transient_environment_add(Manager *m, char **plus) {
|
|
|
|
char **a;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (strv_isempty(plus))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
a = strv_env_merge(2, m->transient_environment, plus);
|
|
|
|
if (!a)
|
2018-11-19 12:22:56 +01:00
|
|
|
return log_oom();
|
2018-10-31 15:49:19 +01:00
|
|
|
|
|
|
|
sanitize_environment(a);
|
|
|
|
|
|
|
|
return strv_free_and_replace(m->transient_environment, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_client_environment_modify(
|
|
|
|
Manager *m,
|
|
|
|
char **minus,
|
|
|
|
char **plus) {
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
char **a = NULL, **b = NULL, **l;
|
2018-10-31 15:49:19 +01:00
|
|
|
|
2013-06-09 07:08:46 +02:00
|
|
|
assert(m);
|
2013-10-01 00:08:30 +02:00
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
if (strv_isempty(minus) && strv_isempty(plus))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
l = m->client_environment;
|
2013-10-01 00:08:30 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
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);
|
2014-09-16 21:11:02 +02:00
|
|
|
if (!b) {
|
|
|
|
strv_free(a);
|
2013-11-19 21:12:59 +01:00
|
|
|
return -ENOMEM;
|
2014-09-16 21:11:02 +02:00
|
|
|
}
|
2013-10-01 00:08:30 +02:00
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
l = b;
|
|
|
|
}
|
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
if (m->client_environment != l)
|
|
|
|
strv_free(m->client_environment);
|
|
|
|
|
2013-11-19 21:12:59 +01:00
|
|
|
if (a != l)
|
|
|
|
strv_free(a);
|
|
|
|
if (b != l)
|
|
|
|
strv_free(b);
|
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
m->client_environment = sanitize_environment(l);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_get_effective_environment(Manager *m, char ***ret) {
|
|
|
|
char **l;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
l = strv_env_merge(2, m->transient_environment, m->client_environment);
|
|
|
|
if (!l)
|
|
|
|
return -ENOMEM;
|
2014-01-12 13:10:40 +01:00
|
|
|
|
2018-10-31 15:49:19 +01:00
|
|
|
*ret = l;
|
2013-06-09 07:08:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-21 18:03:40 +01:00
|
|
|
int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
|
|
|
|
assert(m);
|
|
|
|
|
2020-09-04 17:28:53 +02:00
|
|
|
for (unsigned i = 0; i < _RLIMIT_MAX; i++) {
|
2016-01-14 08:38:12 +01:00
|
|
|
m->rlimit[i] = mfree(m->rlimit[i]);
|
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
if (!default_rlimit[i])
|
|
|
|
continue;
|
2012-03-21 18:03:40 +01:00
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
|
|
|
|
if (!m->rlimit[i])
|
2016-10-18 19:38:41 +02:00
|
|
|
return log_oom();
|
2012-03-21 18:03:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
void manager_recheck_dbus(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Connects to the bus if the dbus service and socket are running. If we are running in user mode this is all
|
|
|
|
* it does. In system mode we'll also connect to the system bus (which will most likely just reuse the
|
|
|
|
* connection of the API bus). That's because the system bus after all runs as service of the system instance,
|
|
|
|
* while in the user instance we can assume it's already there. */
|
|
|
|
|
2018-03-21 12:03:45 +01:00
|
|
|
if (MANAGER_IS_RELOADING(m))
|
|
|
|
return; /* don't check while we are reloading… */
|
|
|
|
|
core: rework how we connect to the bus
This removes the current bus_init() call, as it had multiple problems:
it munged handling of the three bus connections we care about (private,
"api" and system) into one, even though the conditions when which was
ready are very different. It also added redundant logging, as the
individual calls it called all logged on their own anyway.
The three calls bus_init_api(), bus_init_private() and bus_init_system()
are now made public. A new call manager_dbus_is_running() is added that
works much like manager_journal_is_running() and is a lot more careful
when checking whether dbus is around. Optionally it checks the unit's
deserialized_state rather than state, in order to accomodate for cases
where we cant to connect to the bus before deserializing the
"subscribed" list, before coldplugging the units.
manager_recheck_dbus() is added, that works a lot like
manager_recheck_journal() and is invoked in unit_notify(), i.e. when
units change state.
All in all this should make handling a bit more alike to journal
handling, and it also fixes one major bug: when running in user mode
we'll now connect to the system bus early on, without conditionalizing
this in anyway.
2018-02-07 14:52:22 +01:00
|
|
|
if (manager_dbus_is_running(m, false)) {
|
|
|
|
(void) bus_init_api(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
(void) bus_init_system(m);
|
|
|
|
} else {
|
|
|
|
(void) bus_done_api(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_SYSTEM(m))
|
|
|
|
(void) bus_done_system(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 17:42:12 +01:00
|
|
|
static bool manager_journal_is_running(Manager *m) {
|
2011-03-18 04:31:22 +01:00
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2018-10-09 16:15:54 +02:00
|
|
|
if (MANAGER_IS_TEST_RUN(m))
|
2018-02-07 15:06:15 +01:00
|
|
|
return false;
|
|
|
|
|
2018-01-24 17:42:12 +01:00
|
|
|
/* If we are the user manager we can safely assume that the journal is up */
|
2016-02-24 21:24:23 +01:00
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
2018-01-24 17:42:12 +01:00
|
|
|
return true;
|
2011-03-18 04:31:22 +01:00
|
|
|
|
2018-01-24 17:42:12 +01:00
|
|
|
/* Check that the socket is not only up, but in RUNNING state */
|
2012-01-11 03:16:24 +01:00
|
|
|
u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
|
2018-01-24 17:42:12 +01:00
|
|
|
if (!u)
|
|
|
|
return false;
|
|
|
|
if (SOCKET(u)->state != SOCKET_RUNNING)
|
|
|
|
return false;
|
2011-03-18 04:31:22 +01:00
|
|
|
|
2018-01-24 17:42:12 +01:00
|
|
|
/* Similar, check if the daemon itself is fully up, too */
|
2012-01-11 03:16:24 +01:00
|
|
|
u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE);
|
2018-01-24 17:42:12 +01:00
|
|
|
if (!u)
|
|
|
|
return false;
|
2018-02-07 15:07:00 +01:00
|
|
|
if (!IN_SET(SERVICE(u)->state, SERVICE_RELOAD, SERVICE_RUNNING))
|
2018-01-24 17:42:12 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-18 21:02:07 +02:00
|
|
|
void disable_printk_ratelimit(void) {
|
|
|
|
/* Disable kernel's printk ratelimit.
|
|
|
|
*
|
|
|
|
* Logging to /dev/kmsg is most useful during early boot and shutdown, where normal logging
|
|
|
|
* mechanisms are not available. The semantics of this sysctl are such that any kernel command-line
|
|
|
|
* setting takes precedence. */
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sysctl_write("kernel/printk_devkmsg", "on");
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to set sysctl kernel.printk_devkmsg=on: %m");
|
|
|
|
}
|
|
|
|
|
2018-01-24 17:42:12 +01:00
|
|
|
void manager_recheck_journal(Manager *m) {
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Don't bother with this unless we are in the special situation of being PID 1 */
|
|
|
|
if (getpid_cached() != 1)
|
2012-01-11 03:16:24 +01:00
|
|
|
return;
|
2011-03-18 04:31:22 +01:00
|
|
|
|
2018-03-21 12:03:45 +01:00
|
|
|
/* Don't check this while we are reloading, things might still change */
|
|
|
|
if (MANAGER_IS_RELOADING(m))
|
|
|
|
return;
|
|
|
|
|
2018-02-07 15:08:18 +01:00
|
|
|
/* The journal is fully and entirely up? If so, let's permit logging to it, if that's configured. If the
|
|
|
|
* journal is down, don't ever log to it, otherwise we might end up deadlocking ourselves as we might trigger
|
|
|
|
* an activation ourselves we can't fulfill. */
|
|
|
|
log_set_prohibit_ipc(!manager_journal_is_running(m));
|
2018-01-26 14:42:53 +01:00
|
|
|
log_open();
|
2011-03-18 04:31:22 +01:00
|
|
|
}
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
static ShowStatus manager_get_show_status(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (MANAGER_IS_USER(m))
|
|
|
|
return _SHOW_STATUS_INVALID;
|
|
|
|
|
|
|
|
if (m->show_status_overridden != _SHOW_STATUS_INVALID)
|
|
|
|
return m->show_status_overridden;
|
|
|
|
|
|
|
|
return m->show_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool manager_get_show_status_on(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
return show_status_on(manager_get_show_status(m));
|
|
|
|
}
|
2020-04-27 18:14:44 +02:00
|
|
|
|
2020-06-11 11:56:11 +02:00
|
|
|
static void set_show_status_marker(bool b) {
|
|
|
|
if (b)
|
|
|
|
(void) touch("/run/systemd/show-status");
|
|
|
|
else
|
|
|
|
(void) unlink("/run/systemd/show-status");
|
|
|
|
}
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) {
|
2011-09-01 21:05:06 +02:00
|
|
|
assert(m);
|
2020-04-27 11:06:34 +02:00
|
|
|
assert(reason);
|
2020-02-29 17:49:50 +01:00
|
|
|
assert(mode >= 0 && mode < _SHOW_STATUS_MAX);
|
2011-09-01 21:05:06 +02:00
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
if (MANAGER_IS_USER(m))
|
2011-09-01 21:05:06 +02:00
|
|
|
return;
|
|
|
|
|
2020-02-29 11:30:16 +01:00
|
|
|
if (mode == m->show_status)
|
|
|
|
return;
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
if (m->show_status_overridden == _SHOW_STATUS_INVALID) {
|
|
|
|
bool enabled;
|
|
|
|
|
|
|
|
enabled = show_status_on(mode);
|
|
|
|
log_debug("%s (%s) showing of status (%s).",
|
|
|
|
enabled ? "Enabling" : "Disabling",
|
|
|
|
strna(show_status_to_string(mode)),
|
|
|
|
reason);
|
|
|
|
|
2020-06-11 11:56:11 +02:00
|
|
|
set_show_status_marker(enabled);
|
2020-04-27 11:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
m->show_status = mode;
|
|
|
|
}
|
|
|
|
|
2020-06-04 13:25:25 +02:00
|
|
|
void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason) {
|
2020-04-27 11:06:34 +02:00
|
|
|
assert(m);
|
|
|
|
assert(mode < _SHOW_STATUS_MAX);
|
|
|
|
|
|
|
|
if (MANAGER_IS_USER(m))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mode == m->show_status_overridden)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m->show_status_overridden = mode;
|
|
|
|
|
|
|
|
if (mode == _SHOW_STATUS_INVALID)
|
|
|
|
mode = m->show_status;
|
|
|
|
|
2020-02-29 11:30:16 +01:00
|
|
|
log_debug("%s (%s) showing of status (%s).",
|
2020-04-27 11:06:34 +02:00
|
|
|
m->show_status_overridden != _SHOW_STATUS_INVALID ? "Overriding" : "Restoring",
|
2020-02-29 11:30:16 +01:00
|
|
|
strna(show_status_to_string(mode)),
|
|
|
|
reason);
|
2020-04-27 18:14:44 +02:00
|
|
|
|
2020-06-11 11:56:11 +02:00
|
|
|
set_show_status_marker(show_status_on(mode));
|
2011-09-01 21:05:06 +02:00
|
|
|
}
|
|
|
|
|
2016-11-02 10:38:22 +01:00
|
|
|
const char *manager_get_confirm_spawn(Manager *m) {
|
|
|
|
static int last_errno = 0;
|
|
|
|
struct stat st;
|
|
|
|
int r;
|
|
|
|
|
2019-08-20 17:34:16 +02:00
|
|
|
assert(m);
|
|
|
|
|
2016-11-02 10:38:22 +01:00
|
|
|
/* Here's the deal: we want to test the validity of the console but don't want
|
|
|
|
* PID1 to go through the whole console process which might block. But we also
|
|
|
|
* want to warn the user only once if something is wrong with the console so we
|
|
|
|
* cannot do the sanity checks after spawning our children. So here we simply do
|
|
|
|
* really basic tests to hopefully trap common errors.
|
|
|
|
*
|
|
|
|
* If the console suddenly disappear at the time our children will really it
|
|
|
|
* then they will simply fail to acquire it and a positive answer will be
|
2020-08-20 11:23:26 +02:00
|
|
|
* assumed. New children will fall back to /dev/console though.
|
2016-11-02 10:38:22 +01:00
|
|
|
*
|
|
|
|
* Note: TTYs are devices that can come and go any time, and frequently aren't
|
|
|
|
* available yet during early boot (consider a USB rs232 dongle...). If for any
|
2020-08-20 11:23:26 +02:00
|
|
|
* reason the configured console is not ready, we fall back to the default
|
2016-11-02 10:38:22 +01:00
|
|
|
* console. */
|
|
|
|
|
2019-08-20 17:34:16 +02:00
|
|
|
if (!m->confirm_spawn || path_equal(m->confirm_spawn, "/dev/console"))
|
|
|
|
return m->confirm_spawn;
|
2016-11-02 10:38:22 +01:00
|
|
|
|
2019-08-20 17:34:16 +02:00
|
|
|
if (stat(m->confirm_spawn, &st) < 0) {
|
|
|
|
r = -errno;
|
2016-11-02 10:38:22 +01:00
|
|
|
goto fail;
|
2019-08-20 17:34:16 +02:00
|
|
|
}
|
2016-11-02 10:38:22 +01:00
|
|
|
|
|
|
|
if (!S_ISCHR(st.st_mode)) {
|
2019-08-20 17:34:16 +02:00
|
|
|
r = -ENOTTY;
|
2016-11-02 10:38:22 +01:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_errno = 0;
|
2019-08-20 17:34:16 +02:00
|
|
|
return m->confirm_spawn;
|
|
|
|
|
2016-11-02 10:38:22 +01:00
|
|
|
fail:
|
2019-08-20 17:34:16 +02:00
|
|
|
if (last_errno != r)
|
|
|
|
last_errno = log_warning_errno(r, "Failed to open %s, using default console: %m", m->confirm_spawn);
|
|
|
|
|
2016-11-02 10:38:22 +01:00
|
|
|
return "/dev/console";
|
|
|
|
}
|
|
|
|
|
2014-07-07 19:25:31 +02:00
|
|
|
void manager_set_first_boot(Manager *m, bool b) {
|
|
|
|
assert(m);
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
2014-07-07 19:25:31 +02:00
|
|
|
return;
|
|
|
|
|
2015-09-01 02:34:19 +02:00
|
|
|
if (m->first_boot != (int) b) {
|
|
|
|
if (b)
|
|
|
|
(void) touch("/run/systemd/first-boot");
|
|
|
|
else
|
|
|
|
(void) unlink("/run/systemd/first-boot");
|
|
|
|
}
|
2014-07-07 19:25:31 +02:00
|
|
|
|
2015-09-01 02:34:19 +02:00
|
|
|
m->first_boot = b;
|
2014-07-07 19:25:31 +02:00
|
|
|
}
|
|
|
|
|
2016-11-15 09:29:04 +01:00
|
|
|
void manager_disable_confirm_spawn(void) {
|
|
|
|
(void) touch("/run/systemd/confirm_spawn_disabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool manager_is_confirm_spawn_disabled(Manager *m) {
|
|
|
|
if (!m->confirm_spawn)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
|
|
|
|
}
|
|
|
|
|
2020-05-26 10:20:44 +02:00
|
|
|
static bool manager_should_show_status(Manager *m, StatusType type) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!MANAGER_IS_SYSTEM(m))
|
|
|
|
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 (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
|
|
|
|
return true;
|
|
|
|
|
2020-04-27 11:06:34 +02:00
|
|
|
return manager_get_show_status_on(m);
|
2020-05-26 10:20:44 +02:00
|
|
|
}
|
|
|
|
|
2014-10-28 04:02:54 +01:00
|
|
|
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
|
2013-02-28 00:14:40 +01:00
|
|
|
va_list ap;
|
|
|
|
|
2014-11-06 06:05:38 +01:00
|
|
|
/* If m is NULL, assume we're after shutdown and let the messages through. */
|
|
|
|
|
2020-05-26 10:20:44 +02:00
|
|
|
if (m && !manager_should_show_status(m, type))
|
2013-02-28 00:14:40 +01:00
|
|
|
return;
|
|
|
|
|
2013-02-28 00:03:22 +01:00
|
|
|
/* XXX We should totally drop the check for ephemeral here
|
|
|
|
* and thus effectively make 'Type=idle' pointless. */
|
2014-11-06 06:05:38 +01:00
|
|
|
if (type == STATUS_TYPE_EPHEMERAL && m && m->n_on_console > 0)
|
2013-02-28 00:03:22 +01:00
|
|
|
return;
|
|
|
|
|
2013-02-28 00:14:40 +01:00
|
|
|
va_start(ap, format);
|
2018-11-23 17:18:48 +01:00
|
|
|
status_vprintf(status, SHOW_STATUS_ELLIPSIZE|(type == STATUS_TYPE_EPHEMERAL ? SHOW_STATUS_EPHEMERAL : 0), format, ap);
|
2013-02-28 00:14:40 +01:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2013-09-26 20:14:24 +02:00
|
|
|
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
|
|
|
|
char p[strlen(path)+1];
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
strcpy(p, path);
|
2018-05-31 16:39:31 +02:00
|
|
|
path_simplify(p, false);
|
2013-09-26 20:14:24 +02:00
|
|
|
|
|
|
|
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
|
|
|
|
}
|
2014-03-03 17:14:07 +01:00
|
|
|
|
2015-09-11 17:25:35 +02:00
|
|
|
int manager_update_failed_units(Manager *m, Unit *u, bool failed) {
|
2015-02-18 17:22:37 +01:00
|
|
|
unsigned size;
|
2015-09-11 17:25:35 +02:00
|
|
|
int r;
|
2015-02-18 17:22:37 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(u->manager == m);
|
|
|
|
|
|
|
|
size = set_size(m->failed_units);
|
|
|
|
|
2015-03-14 03:10:06 +01:00
|
|
|
if (failed) {
|
2020-06-05 15:12:29 +02:00
|
|
|
r = set_ensure_put(&m->failed_units, NULL, u);
|
2015-09-11 17:25:35 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2015-03-14 03:10:06 +01:00
|
|
|
} else
|
2015-09-11 17:25:35 +02:00
|
|
|
(void) set_remove(m->failed_units, u);
|
2015-02-18 17:22:37 +01:00
|
|
|
|
|
|
|
if (set_size(m->failed_units) != size)
|
|
|
|
bus_manager_send_change_signal(m);
|
2015-09-11 17:25:35 +02:00
|
|
|
|
|
|
|
return 0;
|
2015-02-18 17:22:37 +01:00
|
|
|
}
|
|
|
|
|
2014-03-12 20:55:13 +01:00
|
|
|
ManagerState manager_state(Manager *m) {
|
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-04-04 05:35:22 +02:00
|
|
|
/* Is the special shutdown target active or queued? If so, we are in shutdown state */
|
|
|
|
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
|
|
|
|
if (u && unit_active_or_pending(u))
|
|
|
|
return MANAGER_STOPPING;
|
|
|
|
|
2014-03-12 20:55:13 +01:00
|
|
|
/* Did we ever finish booting? If not then we are still starting up */
|
2017-11-20 21:24:59 +01:00
|
|
|
if (!MANAGER_IS_FINISHED(m)) {
|
2014-08-22 18:07:18 +02:00
|
|
|
|
|
|
|
u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
|
|
|
|
if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
|
|
|
|
return MANAGER_INITIALIZING;
|
|
|
|
|
2014-03-12 20:55:13 +01:00
|
|
|
return MANAGER_STARTING;
|
2014-08-22 18:07:18 +02:00
|
|
|
}
|
2014-03-12 20:55:13 +01:00
|
|
|
|
2017-11-23 17:39:53 +01:00
|
|
|
if (MANAGER_IS_SYSTEM(m)) {
|
|
|
|
/* 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_active_or_pending(u))
|
|
|
|
return MANAGER_MAINTENANCE;
|
2014-03-12 20:55:13 +01:00
|
|
|
|
2017-11-23 17:39:53 +01:00
|
|
|
u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
|
|
|
|
if (u && unit_active_or_pending(u))
|
|
|
|
return MANAGER_MAINTENANCE;
|
|
|
|
}
|
2014-03-12 20:55:13 +01:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
static void manager_unref_uid_internal(
|
|
|
|
Manager *m,
|
|
|
|
Hashmap **uid_refs,
|
|
|
|
uid_t uid,
|
|
|
|
bool destroy_now,
|
|
|
|
int (*_clean_ipc)(uid_t uid)) {
|
|
|
|
|
|
|
|
uint32_t c, n;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(uid_refs);
|
|
|
|
assert(uid_is_valid(uid));
|
|
|
|
assert(_clean_ipc);
|
|
|
|
|
|
|
|
/* A generic implementation, covering both manager_unref_uid() and manager_unref_gid(), under the assumption
|
|
|
|
* that uid_t and gid_t are actually defined the same way, with the same validity rules.
|
|
|
|
*
|
|
|
|
* We store a hashmap where the UID/GID is they key and the value is a 32bit reference counter, whose highest
|
|
|
|
* bit is used as flag for marking UIDs/GIDs whose IPC objects to remove when the last reference to the UID/GID
|
|
|
|
* is dropped. The flag is set to on, once at least one reference from a unit where RemoveIPC= is set is added
|
|
|
|
* on a UID/GID. It is reset when the UID's/GID's reference counter drops to 0 again. */
|
|
|
|
|
|
|
|
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
|
|
|
assert_cc(UID_INVALID == (uid_t) GID_INVALID);
|
|
|
|
|
|
|
|
if (uid == 0) /* We don't keep track of root, and will never destroy it */
|
|
|
|
return;
|
|
|
|
|
|
|
|
c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
|
|
|
|
|
|
|
|
n = c & ~DESTROY_IPC_FLAG;
|
|
|
|
assert(n > 0);
|
|
|
|
n--;
|
|
|
|
|
|
|
|
if (destroy_now && n == 0) {
|
|
|
|
hashmap_remove(*uid_refs, UID_TO_PTR(uid));
|
|
|
|
|
|
|
|
if (c & DESTROY_IPC_FLAG) {
|
|
|
|
log_debug("%s " UID_FMT " is no longer referenced, cleaning up its IPC.",
|
|
|
|
_clean_ipc == clean_ipc_by_uid ? "UID" : "GID",
|
|
|
|
uid);
|
|
|
|
(void) _clean_ipc(uid);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
c = n | (c & DESTROY_IPC_FLAG);
|
|
|
|
assert_se(hashmap_update(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)) >= 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager_unref_uid(Manager *m, uid_t uid, bool destroy_now) {
|
|
|
|
manager_unref_uid_internal(m, &m->uid_refs, uid, destroy_now, clean_ipc_by_uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now) {
|
|
|
|
manager_unref_uid_internal(m, &m->gid_refs, (uid_t) gid, destroy_now, clean_ipc_by_gid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_ref_uid_internal(
|
|
|
|
Manager *m,
|
|
|
|
Hashmap **uid_refs,
|
|
|
|
uid_t uid,
|
|
|
|
bool clean_ipc) {
|
|
|
|
|
|
|
|
uint32_t c, n;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(uid_refs);
|
|
|
|
assert(uid_is_valid(uid));
|
|
|
|
|
|
|
|
/* A generic implementation, covering both manager_ref_uid() and manager_ref_gid(), under the assumption
|
|
|
|
* that uid_t and gid_t are actually defined the same way, with the same validity rules. */
|
|
|
|
|
|
|
|
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
|
|
|
assert_cc(UID_INVALID == (uid_t) GID_INVALID);
|
|
|
|
|
|
|
|
if (uid == 0) /* We don't keep track of root, and will never destroy it */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
|
|
|
|
|
|
|
|
n = c & ~DESTROY_IPC_FLAG;
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n & DESTROY_IPC_FLAG) /* check for overflow */
|
|
|
|
return -EOVERFLOW;
|
|
|
|
|
|
|
|
c = n | (c & DESTROY_IPC_FLAG) | (clean_ipc ? DESTROY_IPC_FLAG : 0);
|
|
|
|
|
|
|
|
return hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_ref_uid(Manager *m, uid_t uid, bool clean_ipc) {
|
|
|
|
return manager_ref_uid_internal(m, &m->uid_refs, uid, clean_ipc);
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_ref_gid(Manager *m, gid_t gid, bool clean_ipc) {
|
|
|
|
return manager_ref_uid_internal(m, &m->gid_refs, (uid_t) gid, clean_ipc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void manager_vacuum_uid_refs_internal(
|
|
|
|
Manager *m,
|
|
|
|
Hashmap **uid_refs,
|
|
|
|
int (*_clean_ipc)(uid_t uid)) {
|
|
|
|
|
|
|
|
void *p, *k;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(uid_refs);
|
|
|
|
assert(_clean_ipc);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH_KEY(p, k, *uid_refs) {
|
2016-08-01 19:24:40 +02:00
|
|
|
uint32_t c, n;
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
uid = PTR_TO_UID(k);
|
|
|
|
c = PTR_TO_UINT32(p);
|
|
|
|
|
|
|
|
n = c & ~DESTROY_IPC_FLAG;
|
|
|
|
if (n > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c & DESTROY_IPC_FLAG) {
|
|
|
|
log_debug("Found unreferenced %s " UID_FMT " after reload/reexec. Cleaning up.",
|
|
|
|
_clean_ipc == clean_ipc_by_uid ? "UID" : "GID",
|
|
|
|
uid);
|
|
|
|
(void) _clean_ipc(uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_se(hashmap_remove(*uid_refs, k) == p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-27 08:54:44 +02:00
|
|
|
static void manager_vacuum_uid_refs(Manager *m) {
|
2016-08-01 19:24:40 +02:00
|
|
|
manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid);
|
|
|
|
}
|
|
|
|
|
2020-04-27 08:54:44 +02:00
|
|
|
static void manager_vacuum_gid_refs(Manager *m) {
|
2016-08-01 19:24:40 +02:00
|
|
|
manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid);
|
|
|
|
}
|
|
|
|
|
2020-04-27 08:54:44 +02:00
|
|
|
static void manager_vacuum(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Release any dynamic users no longer referenced */
|
|
|
|
dynamic_user_vacuum(m, true);
|
|
|
|
|
|
|
|
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
|
|
|
|
manager_vacuum_uid_refs(m);
|
|
|
|
manager_vacuum_gid_refs(m);
|
|
|
|
|
|
|
|
/* Release any runtimes no longer referenced */
|
|
|
|
exec_runtime_vacuum(m);
|
|
|
|
}
|
|
|
|
|
2016-08-01 19:24:40 +02:00
|
|
|
int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
|
struct buffer {
|
|
|
|
uid_t uid;
|
|
|
|
gid_t gid;
|
|
|
|
char unit_name[UNIT_NAME_MAX+1];
|
|
|
|
} _packed_ buffer;
|
|
|
|
|
|
|
|
Manager *m = userdata;
|
|
|
|
ssize_t l;
|
|
|
|
size_t n;
|
|
|
|
Unit *u;
|
|
|
|
|
|
|
|
assert_se(source);
|
|
|
|
assert_se(m);
|
|
|
|
|
|
|
|
/* Invoked whenever a child process succeeded resolving its user/group to use and sent us the resulting UID/GID
|
|
|
|
* in a datagram. We parse the datagram here and pass it off to the unit, so that it can add a reference to the
|
|
|
|
* UID/GID so that it can destroy the UID/GID's IPC objects when the reference counter drops to 0. */
|
|
|
|
|
|
|
|
l = recv(fd, &buffer, sizeof(buffer), MSG_DONTWAIT);
|
|
|
|
if (l < 0) {
|
2017-10-04 16:01:32 +02:00
|
|
|
if (IN_SET(errno, EINTR, EAGAIN))
|
2016-08-01 19:24:40 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return log_error_errno(errno, "Failed to read from user lookup fd: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((size_t) l <= offsetof(struct buffer, unit_name)) {
|
|
|
|
log_warning("Received too short user lookup message, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((size_t) l > offsetof(struct buffer, unit_name) + UNIT_NAME_MAX) {
|
|
|
|
log_warning("Received too long user lookup message, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!uid_is_valid(buffer.uid) && !gid_is_valid(buffer.gid)) {
|
|
|
|
log_warning("Got user lookup message with invalid UID/GID pair, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = (size_t) l - offsetof(struct buffer, unit_name);
|
|
|
|
if (memchr(buffer.unit_name, 0, n)) {
|
|
|
|
log_warning("Received lookup message with embedded NUL character, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.unit_name[n] = 0;
|
|
|
|
u = manager_get_unit(m, buffer.unit_name);
|
|
|
|
if (!u) {
|
|
|
|
log_debug("Got user lookup message but unit doesn't exist, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_unit_debug(u, "User lookup succeeded: uid=" UID_FMT " gid=" GID_FMT, buffer.uid, buffer.gid);
|
|
|
|
|
|
|
|
unit_notify_user_lookup(u, buffer.uid, buffer.gid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-07 11:27:07 +01:00
|
|
|
char *manager_taint_string(Manager *m) {
|
2017-12-07 11:35:02 +01:00
|
|
|
_cleanup_free_ char *destination = NULL, *overflowuid = NULL, *overflowgid = NULL;
|
2017-12-07 11:27:07 +01:00
|
|
|
char *buf, *e;
|
|
|
|
int r;
|
|
|
|
|
2017-12-14 12:44:21 +01:00
|
|
|
/* Returns a "taint string", e.g. "local-hwclock:var-run-bad".
|
|
|
|
* Only things that are detected at runtime should be tagged
|
|
|
|
* here. For stuff that is set during compilation, emit a warning
|
|
|
|
* in the configuration phase. */
|
|
|
|
|
2017-12-07 11:27:07 +01:00
|
|
|
assert(m);
|
|
|
|
|
|
|
|
buf = new(char, sizeof("split-usr:"
|
|
|
|
"cgroups-missing:"
|
|
|
|
"local-hwclock:"
|
|
|
|
"var-run-bad:"
|
2017-12-07 11:35:02 +01:00
|
|
|
"overflowuid-not-65534:"
|
|
|
|
"overflowgid-not-65534:"));
|
2017-12-07 11:27:07 +01:00
|
|
|
if (!buf)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
e = buf;
|
2017-12-10 11:58:01 +01:00
|
|
|
buf[0] = 0;
|
2017-12-07 11:27:07 +01:00
|
|
|
|
|
|
|
if (m->taint_usr)
|
|
|
|
e = stpcpy(e, "split-usr:");
|
|
|
|
|
|
|
|
if (access("/proc/cgroups", F_OK) < 0)
|
|
|
|
e = stpcpy(e, "cgroups-missing:");
|
|
|
|
|
|
|
|
if (clock_is_localtime(NULL) > 0)
|
|
|
|
e = stpcpy(e, "local-hwclock:");
|
|
|
|
|
|
|
|
r = readlink_malloc("/var/run", &destination);
|
|
|
|
if (r < 0 || !PATH_IN_SET(destination, "../run", "/run"))
|
|
|
|
e = stpcpy(e, "var-run-bad:");
|
|
|
|
|
2017-12-07 11:35:02 +01:00
|
|
|
r = read_one_line_file("/proc/sys/kernel/overflowuid", &overflowuid);
|
|
|
|
if (r >= 0 && !streq(overflowuid, "65534"))
|
|
|
|
e = stpcpy(e, "overflowuid-not-65534:");
|
|
|
|
|
|
|
|
r = read_one_line_file("/proc/sys/kernel/overflowgid", &overflowgid);
|
|
|
|
if (r >= 0 && !streq(overflowgid, "65534"))
|
|
|
|
e = stpcpy(e, "overflowgid-not-65534:");
|
|
|
|
|
2017-12-07 11:27:07 +01:00
|
|
|
/* remove the last ':' */
|
|
|
|
if (e != buf)
|
|
|
|
e[-1] = 0;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:59:55 +01:00
|
|
|
void manager_ref_console(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
m->n_on_console++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager_unref_console(Manager *m) {
|
|
|
|
|
|
|
|
assert(m->n_on_console > 0);
|
|
|
|
m->n_on_console--;
|
|
|
|
|
|
|
|
if (m->n_on_console == 0)
|
|
|
|
m->no_console_output = false; /* unset no_console_output flag, since the console is definitely free now */
|
|
|
|
}
|
|
|
|
|
2018-05-30 17:57:23 +02:00
|
|
|
void manager_override_log_level(Manager *m, int level) {
|
|
|
|
_cleanup_free_ char *s = NULL;
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!m->log_level_overridden) {
|
|
|
|
m->original_log_level = log_get_max_level();
|
|
|
|
m->log_level_overridden = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) log_level_to_string_alloc(level, &s);
|
|
|
|
log_info("Setting log level to %s.", strna(s));
|
|
|
|
|
|
|
|
log_set_max_level(level);
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager_restore_original_log_level(Manager *m) {
|
|
|
|
_cleanup_free_ char *s = NULL;
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!m->log_level_overridden)
|
|
|
|
return;
|
|
|
|
|
|
|
|
(void) log_level_to_string_alloc(m->original_log_level, &s);
|
|
|
|
log_info("Restoring log level to original (%s).", strna(s));
|
|
|
|
|
|
|
|
log_set_max_level(m->original_log_level);
|
|
|
|
m->log_level_overridden = false;
|
|
|
|
}
|
|
|
|
|
2018-06-01 18:21:03 +02:00
|
|
|
void manager_override_log_target(Manager *m, LogTarget target) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!m->log_target_overridden) {
|
|
|
|
m->original_log_target = log_get_target();
|
|
|
|
m->log_target_overridden = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info("Setting log target to %s.", log_target_to_string(target));
|
|
|
|
log_set_target(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager_restore_original_log_target(Manager *m) {
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (!m->log_target_overridden)
|
|
|
|
return;
|
|
|
|
|
|
|
|
log_info("Restoring log target to original %s.", log_target_to_string(m->original_log_target));
|
|
|
|
|
|
|
|
log_set_target(m->original_log_target);
|
|
|
|
m->log_target_overridden = false;
|
|
|
|
}
|
|
|
|
|
2018-07-22 06:41:44 +02:00
|
|
|
ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s) {
|
|
|
|
if (in_initrd() &&
|
|
|
|
s >= MANAGER_TIMESTAMP_SECURITY_START &&
|
|
|
|
s <= MANAGER_TIMESTAMP_UNITS_LOAD_FINISH)
|
|
|
|
return s - MANAGER_TIMESTAMP_SECURITY_START + MANAGER_TIMESTAMP_INITRD_SECURITY_START;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2014-03-12 20:55:13 +01:00
|
|
|
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
|
2014-08-22 18:07:18 +02:00
|
|
|
[MANAGER_INITIALIZING] = "initializing",
|
2014-03-12 20:55:13 +01:00
|
|
|
[MANAGER_STARTING] = "starting",
|
|
|
|
[MANAGER_RUNNING] = "running",
|
|
|
|
[MANAGER_DEGRADED] = "degraded",
|
|
|
|
[MANAGER_MAINTENANCE] = "maintenance",
|
|
|
|
[MANAGER_STOPPING] = "stopping",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
|
2017-11-20 21:01:13 +01:00
|
|
|
|
|
|
|
static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
|
|
|
|
[MANAGER_TIMESTAMP_FIRMWARE] = "firmware",
|
|
|
|
[MANAGER_TIMESTAMP_LOADER] = "loader",
|
|
|
|
[MANAGER_TIMESTAMP_KERNEL] = "kernel",
|
|
|
|
[MANAGER_TIMESTAMP_INITRD] = "initrd",
|
|
|
|
[MANAGER_TIMESTAMP_USERSPACE] = "userspace",
|
|
|
|
[MANAGER_TIMESTAMP_FINISH] = "finish",
|
|
|
|
[MANAGER_TIMESTAMP_SECURITY_START] = "security-start",
|
|
|
|
[MANAGER_TIMESTAMP_SECURITY_FINISH] = "security-finish",
|
|
|
|
[MANAGER_TIMESTAMP_GENERATORS_START] = "generators-start",
|
|
|
|
[MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
|
|
|
|
[MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
|
|
|
|
[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
|
2018-07-22 06:41:44 +02:00
|
|
|
[MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start",
|
|
|
|
[MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish",
|
|
|
|
[MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start",
|
|
|
|
[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH] = "initrd-generators-finish",
|
|
|
|
[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start",
|
|
|
|
[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH] = "initrd-units-load-finish",
|
2017-11-20 21:01:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp);
|
2019-03-19 19:05:19 +01:00
|
|
|
|
|
|
|
static const char* const oom_policy_table[_OOM_POLICY_MAX] = {
|
|
|
|
[OOM_CONTINUE] = "continue",
|
|
|
|
[OOM_STOP] = "stop",
|
|
|
|
[OOM_KILL] = "kill",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy);
|