Merge pull request #24018 from keszybz/generator-cleanups
Make generators easier to test, fix various corner issues
This commit is contained in:
@@ -51,6 +51,9 @@ All tools:
|
||||
* `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful
|
||||
for debugging.
|
||||
|
||||
* `$SYSTEMD_SYSROOT_FSTAB` — if set, use this path instead of
|
||||
`/sysroot/etc/fstab`. Only useful for debugging `systemd-fstab-generator`.
|
||||
|
||||
* `$SYSTEMD_CRYPTTAB` — if set, use this path instead of `/etc/crypttab`. Only
|
||||
useful for debugging. Currently only supported by
|
||||
`systemd-cryptsetup-generator`.
|
||||
|
||||
+9
-8
@@ -272,13 +272,14 @@
|
||||
<varlistentry>
|
||||
<term>BARRIER=1</term>
|
||||
|
||||
<listitem><para>Tells the service manager that the client is explicitly requesting synchronization by means of
|
||||
closing the file descriptor sent with this command. The service manager guarantees that the processing of a <varname>
|
||||
BARRIER=1</varname> command will only happen after all previous notification messages sent before this command
|
||||
have been processed. Hence, this command accompanied with a single file descriptor can be used to synchronize
|
||||
against reception of all previous status messages. Note that this command cannot be mixed with other notifications,
|
||||
and has to be sent in a separate message to the service manager, otherwise all assignments will be ignored. Note that
|
||||
sending 0 or more than 1 file descriptor with this command is a violation of the protocol.</para></listitem>
|
||||
<listitem><para>Tells the service manager that the client is explicitly requesting synchronization by
|
||||
means of closing the file descriptor sent with this command. The service manager guarantees that the
|
||||
processing of a <varname>BARRIER=1</varname> command will only happen after all previous notification
|
||||
messages sent before this command have been processed. Hence, this command accompanied with a single
|
||||
file descriptor can be used to synchronize against reception of all previous status messages. Note
|
||||
that this command cannot be mixed with other notifications, and has to be sent in a separate message
|
||||
to the service manager, otherwise all assignments will be ignored. Note that sending 0 or more than 1
|
||||
file descriptor with this command is a violation of the protocol.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
@@ -341,7 +342,7 @@
|
||||
|
||||
<para><function>sd_notify_barrier()</function> allows the caller to
|
||||
synchronize against reception of previously sent notification messages
|
||||
and uses the <literal>BARRIER=1</literal> command. It takes a relative
|
||||
and uses the <varname>BARRIER=1</varname> command. It takes a relative
|
||||
<varname>timeout</varname> value in microseconds which is passed to
|
||||
<citerefentry><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum>
|
||||
</citerefentry>. A value of UINT64_MAX is interpreted as infinite timeout.
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
for more information about special <filename>/etc/fstab</filename>
|
||||
mount options this generator understands.</para>
|
||||
|
||||
<para>One special topic is handling of symbolic links. Historical init
|
||||
<para>One special topic is handling of symbolic links. Historical init
|
||||
implementations supported symlinks in <filename>/etc/fstab</filename>.
|
||||
Because mount units will refuse mounts where the target is a symbolic link,
|
||||
this generator will resolve any symlinks as far as possible when processing
|
||||
@@ -251,8 +251,8 @@
|
||||
<citerefentry><refentrytitle>systemd.swap</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<ulink url="https://systemd.io/ENVIRONMENT/">Known Environment Variables</ulink>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
+11
-10
@@ -26,8 +26,8 @@
|
||||
<cmdsynopsis>
|
||||
<command index='false'>/path/to/generator</command>
|
||||
<arg choice="plain"><replaceable>normal-dir</replaceable></arg>
|
||||
<arg choice="plain"><replaceable>early-dir</replaceable></arg>
|
||||
<arg choice="plain"><replaceable>late-dir</replaceable></arg>
|
||||
<arg choice="option"><replaceable>early-dir</replaceable></arg>
|
||||
<arg choice="option"><replaceable>late-dir</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<para>
|
||||
@@ -56,13 +56,13 @@
|
||||
that they can extend the unit file hierarchy the service manager subsequently loads and operates
|
||||
on.</para>
|
||||
|
||||
<para>Each generator is called with three directory paths that are to be used for generator output. In
|
||||
these three directories, generators may dynamically generate unit files (regular ones, instances, as well
|
||||
as templates), unit file <filename>.d/</filename> drop-ins, and create symbolic links to unit files to
|
||||
add additional dependencies, create aliases, or instantiate existing templates. Those directories are
|
||||
included in the unit load path of
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, allowing
|
||||
generated configuration to extend or override existing definitions.</para>
|
||||
<para><command>systemd</command> will call each generator with three directory paths that are to be used
|
||||
for generator output. In these three directories, generators may dynamically generate unit files (regular
|
||||
ones, instances, as well as templates), unit file <filename>.d/</filename> drop-ins, and create symbolic
|
||||
links to unit files to add additional dependencies, create aliases, or instantiate existing templates.
|
||||
Those directories are included in the unit load path, allowing generated configuration to extend or
|
||||
override existing definitions. For tests, generators may be called with just one argument; the generator
|
||||
should assume that all three paths are the same in that case.</para>
|
||||
|
||||
<para>Directory paths for generator output differ by priority: <filename>…/generator.early</filename> has
|
||||
priority higher than the admin configuration in <filename>/etc/</filename>, while
|
||||
@@ -96,7 +96,8 @@
|
||||
<para>Generators are invoked with three arguments: paths to directories where generators can place their
|
||||
generated unit files or symlinks. By default those paths are runtime directories that are included in the
|
||||
search path of <command>systemd</command>, but a generator may be called with different paths for
|
||||
debugging purposes.</para>
|
||||
debugging purposes. If only one argument is provided, the generator should use the same directory as the
|
||||
the three output paths.</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
|
||||
+2
-20
@@ -1153,30 +1153,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
}
|
||||
|
||||
static bool should_parse_proc_cmdline(void) {
|
||||
const char *e;
|
||||
pid_t p;
|
||||
|
||||
/* PID1 always reads the kernel command line. */
|
||||
if (getpid_cached() == 1)
|
||||
return true;
|
||||
|
||||
/* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd,
|
||||
* or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */
|
||||
e = getenv("SYSTEMD_EXEC_PID");
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (streq(e, "*"))
|
||||
/* For testing. */
|
||||
return true;
|
||||
|
||||
if (parse_pid(e, &p) < 0) {
|
||||
/* We know that systemd sets the variable correctly. Something else must have set it. */
|
||||
log_debug("Failed to parse \"$SYSTEMD_EXEC_PID=%s\". Ignoring.", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return getpid_cached() == p;
|
||||
/* Otherwise, parse the commandline if invoked directly by systemd. */
|
||||
return invoked_by_systemd();
|
||||
}
|
||||
|
||||
void log_parse_environment_variables(void) {
|
||||
|
||||
@@ -1579,6 +1579,30 @@ bool invoked_as(char *argv[], const char *token) {
|
||||
return strstr(last_path_component(argv[0]), token);
|
||||
}
|
||||
|
||||
bool invoked_by_systemd(void) {
|
||||
int r;
|
||||
|
||||
/* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd,
|
||||
* or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */
|
||||
const char *e = getenv("SYSTEMD_EXEC_PID");
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (streq(e, "*"))
|
||||
/* For testing. */
|
||||
return true;
|
||||
|
||||
pid_t p;
|
||||
r = parse_pid(e, &p);
|
||||
if (r < 0) {
|
||||
/* We know that systemd sets the variable correctly. Something else must have set it. */
|
||||
log_debug_errno(r, "Failed to parse \"SYSTEMD_EXEC_PID=%s\", ignoring: %m", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return getpid_cached() == p;
|
||||
}
|
||||
|
||||
_noreturn_ void freeze(void) {
|
||||
log_close();
|
||||
|
||||
|
||||
@@ -190,6 +190,8 @@ int setpriority_closest(int priority);
|
||||
|
||||
bool invoked_as(char *argv[], const char *token);
|
||||
|
||||
bool invoked_by_systemd(void);
|
||||
|
||||
_noreturn_ void freeze(void);
|
||||
|
||||
bool argv_looks_like_help(int argc, char **argv);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "efi-loader.h"
|
||||
@@ -10,62 +9,47 @@
|
||||
#include "mkdir.h"
|
||||
#include "special.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
#include "virt.h"
|
||||
|
||||
/* This generator pulls systemd-bless-boot.service into the initial transaction if the "LoaderBootCountPath" EFI
|
||||
* variable is set, i.e. the system boots up with boot counting in effect, which means we should mark the boot as
|
||||
* "good" if we manage to boot up far enough. */
|
||||
/* This generator pulls systemd-bless-boot.service into the initial transaction if the "LoaderBootCountPath"
|
||||
* EFI variable is set, i.e. the system boots up with boot counting in effect, which means we should mark the
|
||||
* boot as "good" if we manage to boot up far enough. */
|
||||
|
||||
static const char *arg_dest = "/tmp";
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *p;
|
||||
|
||||
log_setup_generator();
|
||||
|
||||
if (argc > 1 && argc != 4) {
|
||||
log_error("This program takes three or no arguments.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
arg_dest = argv[2];
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
|
||||
if (in_initrd() > 0) {
|
||||
log_debug("Skipping generator, running in the initrd.");
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (detect_container() > 0) {
|
||||
log_debug("Skipping generator, running in a container.");
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_efi_boot()) {
|
||||
log_debug("Skipping generator, not an EFI boot.");
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderBootCountPath)), F_OK) < 0) {
|
||||
|
||||
if (errno == ENOENT) {
|
||||
log_debug_errno(errno, "Skipping generator, not booted with boot counting in effect.");
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_error_errno(errno, "Failed to check if LoaderBootCountPath EFI variable exists: %m");
|
||||
return EXIT_FAILURE;
|
||||
return log_error_errno(errno, "Failed to check if LoaderBootCountPath EFI variable exists: %m");
|
||||
}
|
||||
|
||||
/* We pull this in from basic.target so that it ends up in all "regular" boot ups, but not in rescue.target or
|
||||
* even emergency.target. */
|
||||
p = strjoina(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/systemd-bless-boot.service");
|
||||
/* We pull this in from basic.target so that it ends up in all "regular" boot ups, but not in
|
||||
* rescue.target or even emergency.target. */
|
||||
const char *p = strjoina(dest_early, "/" SPECIAL_BASIC_TARGET ".wants/systemd-bless-boot.service");
|
||||
(void) mkdir_parents(p, 0755);
|
||||
if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-bless-boot.service", p) < 0) {
|
||||
log_error_errno(errno, "Failed to create symlink '%s': %m", p);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-bless-boot.service", p) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink '%s': %m", p);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
||||
|
||||
+38
-35
@@ -2530,14 +2530,14 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Make sure it's NUL-terminated, then parse it to obtain the tags list */
|
||||
/* Make sure it's NUL-terminated, then parse it to obtain the tags list. */
|
||||
buf[n] = 0;
|
||||
tags = strv_split_newlines(buf);
|
||||
if (!tags) {
|
||||
@@ -2545,7 +2545,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* possibly a barrier fd, let's see */
|
||||
/* Possibly a barrier fd, let's see. */
|
||||
if (manager_process_barrier_fd(tags, fds))
|
||||
return 0;
|
||||
|
||||
@@ -2566,8 +2566,8 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
|
||||
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. */
|
||||
/* 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) {
|
||||
manager_invoke_notify_message(m, u1, ucred, tags, fds);
|
||||
found = true;
|
||||
@@ -2620,8 +2620,8 @@ static int manager_dispatch_sigchld(sd_event_source *source, void *userdata) {
|
||||
assert(source);
|
||||
assert(m);
|
||||
|
||||
/* First we call waitid() for a PID and do not reap the zombie. That way we can still access /proc/$PID for it
|
||||
* while it is a zombie. */
|
||||
/* First we call waitid() for a PID and do not reap the zombie. That way we can still access
|
||||
* /proc/$PID for it while it is a zombie. */
|
||||
|
||||
if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
|
||||
|
||||
@@ -2988,15 +2988,15 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32
|
||||
assert(m);
|
||||
assert(m->idle_pipe[2] == fd);
|
||||
|
||||
/* 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. */
|
||||
/* 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. */
|
||||
m->no_console_output = m->n_on_console > 0;
|
||||
|
||||
/* 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. */
|
||||
/* 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. */
|
||||
manager_close_idle_pipe(m);
|
||||
|
||||
return 0;
|
||||
@@ -3092,8 +3092,8 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Permit addressing units by invocation ID: if the passed bus path is suffixed by a 128bit ID then we use it
|
||||
* as invocation ID. */
|
||||
/* 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);
|
||||
@@ -3915,10 +3915,10 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
|
||||
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. */
|
||||
/* 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. */
|
||||
|
||||
if (MANAGER_IS_RELOADING(m))
|
||||
return; /* don't check while we are reloading… */
|
||||
@@ -3990,9 +3990,9 @@ void manager_recheck_journal(Manager *m) {
|
||||
if (MANAGER_IS_RELOADING(m))
|
||||
return;
|
||||
|
||||
/* 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. */
|
||||
/* 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));
|
||||
log_open();
|
||||
}
|
||||
@@ -4264,13 +4264,14 @@ static void manager_unref_uid_internal(
|
||||
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.
|
||||
/* 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 key is the UID/GID 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. */
|
||||
* We store a hashmap where the key is the UID/GID 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);
|
||||
@@ -4318,8 +4319,9 @@ static int manager_ref_uid_internal(
|
||||
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. */
|
||||
/* 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);
|
||||
@@ -4419,9 +4421,10 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
|
||||
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. */
|
||||
/* 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) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "escape.h"
|
||||
#include "glyph-util.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "path-lookup.h"
|
||||
#include "strv.h"
|
||||
|
||||
@@ -80,20 +81,19 @@ static int load_and_print(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
static int run(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
if (argc > 1) {
|
||||
log_error("This program takes no arguments.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
|
||||
|
||||
r = load_and_print();
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to load environment.d: %m");
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
return log_error_errno(r, "Failed to load environment.d: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ static void start_target(const char *target, const char *mode) {
|
||||
|
||||
log_info("Running request %s/start/%s", target, mode);
|
||||
|
||||
/* Start these units only if we can replace base.target with it */
|
||||
/* Start this unit only if we can replace basic.target with it */
|
||||
r = sd_bus_call_method(bus,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
|
||||
@@ -92,6 +92,7 @@ static int write_what(FILE *f, const char *what) {
|
||||
}
|
||||
|
||||
static int add_swap(
|
||||
const char *source,
|
||||
const char *what,
|
||||
struct mntent *me,
|
||||
MountPointFlags flags) {
|
||||
@@ -122,7 +123,7 @@ static int add_swap(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
||||
|
||||
r = generator_open_unit_file(arg_dest, fstab_path(), name, &f);
|
||||
r = generator_open_unit_file(arg_dest, source, name, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -130,7 +131,7 @@ static int add_swap(
|
||||
"[Unit]\n"
|
||||
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
|
||||
"SourcePath=%s\n",
|
||||
fstab_path());
|
||||
source);
|
||||
|
||||
r = generator_write_blockdev_dependency(f, what);
|
||||
if (r < 0)
|
||||
@@ -188,7 +189,7 @@ static bool mount_in_initrd(struct mntent *me) {
|
||||
assert(me);
|
||||
|
||||
return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
|
||||
streq(me->mnt_dir, "/usr");
|
||||
path_equal(me->mnt_dir, "/usr");
|
||||
}
|
||||
|
||||
static int write_timeout(
|
||||
@@ -339,6 +340,7 @@ static int write_extra_dependencies(FILE *f, const char *opts) {
|
||||
}
|
||||
|
||||
static int add_mount(
|
||||
const char *source,
|
||||
const char *dest,
|
||||
const char *what,
|
||||
const char *where,
|
||||
@@ -347,8 +349,7 @@ static int add_mount(
|
||||
const char *opts,
|
||||
int passno,
|
||||
MountPointFlags flags,
|
||||
const char *post,
|
||||
const char *source) {
|
||||
const char *target_unit) {
|
||||
|
||||
_cleanup_free_ char
|
||||
*name = NULL,
|
||||
@@ -362,7 +363,7 @@ static int add_mount(
|
||||
assert(what);
|
||||
assert(where);
|
||||
assert(opts);
|
||||
assert(post);
|
||||
assert(target_unit);
|
||||
assert(source);
|
||||
|
||||
if (streq_ptr(fstype, "autofs"))
|
||||
@@ -406,7 +407,7 @@ static int add_mount(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
||||
|
||||
r = generator_open_unit_file(dest, fstab_path(), name, &f);
|
||||
r = generator_open_unit_file(dest, source, name, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -434,10 +435,10 @@ static int add_mount(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Order the mount unit we generate relative to the post unit, so that DefaultDependencies= on the
|
||||
/* Order the mount unit we generate relative to target_unit, so that DefaultDependencies= on the
|
||||
* target unit won't affect us. */
|
||||
if (post && !FLAGS_SET(flags, MOUNT_NOFAIL))
|
||||
fprintf(f, "Before=%s\n", post);
|
||||
if (!FLAGS_SET(flags, MOUNT_NOFAIL))
|
||||
fprintf(f, "Before=%s\n", target_unit);
|
||||
|
||||
if (passno != 0) {
|
||||
r = generator_write_fsck_deps(f, dest, what, where, fstype);
|
||||
@@ -505,14 +506,14 @@ static int add_mount(
|
||||
}
|
||||
|
||||
if (flags & MOUNT_GROWFS) {
|
||||
r = generator_hook_up_growfs(dest, where, post);
|
||||
r = generator_hook_up_growfs(dest, where, target_unit);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(flags, MOUNT_AUTOMOUNT)) {
|
||||
if (!FLAGS_SET(flags, MOUNT_NOAUTO) && strv_isempty(wanted_by) && strv_isempty(required_by)) {
|
||||
r = generator_add_symlink(dest, post,
|
||||
r = generator_add_symlink(dest, target_unit,
|
||||
(flags & MOUNT_NOFAIL) ? "wants" : "requires", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -536,7 +537,7 @@ static int add_mount(
|
||||
|
||||
f = safe_fclose(f);
|
||||
|
||||
r = generator_open_unit_file(dest, fstab_path(), automount_name, &f);
|
||||
r = generator_open_unit_file(dest, source, automount_name, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -560,7 +561,7 @@ static int add_mount(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write unit file %s: %m", automount_name);
|
||||
|
||||
r = generator_add_symlink(dest, post,
|
||||
r = generator_add_symlink(dest, target_unit,
|
||||
(flags & MOUNT_NOFAIL) ? "wants" : "requires", automount_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -569,13 +570,21 @@ static int add_mount(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* sysroot_fstab_path(void) {
|
||||
return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab";
|
||||
}
|
||||
|
||||
static int parse_fstab(bool initrd) {
|
||||
_cleanup_endmntent_ FILE *f = NULL;
|
||||
const char *fstab;
|
||||
struct mntent *me;
|
||||
int r = 0;
|
||||
|
||||
fstab = initrd ? "/sysroot/etc/fstab" : fstab_path();
|
||||
if (initrd)
|
||||
fstab = sysroot_fstab_path();
|
||||
else
|
||||
fstab = fstab_path();
|
||||
|
||||
log_debug("Parsing %s...", fstab);
|
||||
|
||||
f = setmntent(fstab, "re");
|
||||
@@ -622,13 +631,25 @@ static int parse_fstab(bool initrd) {
|
||||
* mount units, but causes problems since it historically worked to have symlinks in e.g.
|
||||
* /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
|
||||
* where a symlink refers to another mount target; this works assuming the sub-mountpoint
|
||||
* target is the final directory. */
|
||||
* target is the final directory.
|
||||
*
|
||||
* FIXME: when chase_symlinks() learns to chase non-existent paths, use this here and
|
||||
* drop the prefixing with /sysroot on error below.
|
||||
*/
|
||||
k = chase_symlinks(where, initrd ? "/sysroot" : NULL,
|
||||
CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
|
||||
&canonical_where, NULL);
|
||||
if (k < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
|
||||
log_debug_errno(k, "Failed to read symlink target for %s, ignoring: %m", where);
|
||||
else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
|
||||
if (k < 0) {
|
||||
/* If we can't canonicalize, continue as if it wasn't a symlink */
|
||||
log_debug_errno(k, "Failed to read symlink target for %s, using as-is: %m", where);
|
||||
|
||||
if (initrd) {
|
||||
canonical_where = path_join("/sysroot", where);
|
||||
if (!canonical_where)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
} else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
|
||||
canonical_where = mfree(canonical_where);
|
||||
else
|
||||
log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where);
|
||||
@@ -650,10 +671,9 @@ static int parse_fstab(bool initrd) {
|
||||
nofail * MOUNT_NOFAIL;
|
||||
|
||||
if (streq(me->mnt_type, "swap"))
|
||||
k = add_swap(what, me, flags);
|
||||
k = add_swap(fstab, what, me, flags);
|
||||
else {
|
||||
bool rw_only, automount;
|
||||
const char *post;
|
||||
|
||||
rw_only = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
|
||||
automount = fstab_test_option(me->mnt_opts,
|
||||
@@ -663,14 +683,13 @@ static int parse_fstab(bool initrd) {
|
||||
flags |= rw_only * MOUNT_RW_ONLY |
|
||||
automount * MOUNT_AUTOMOUNT;
|
||||
|
||||
if (initrd)
|
||||
post = SPECIAL_INITRD_FS_TARGET;
|
||||
else if (mount_is_network(me))
|
||||
post = SPECIAL_REMOTE_FS_TARGET;
|
||||
else
|
||||
post = SPECIAL_LOCAL_FS_TARGET;
|
||||
const char *target_unit =
|
||||
initrd ? SPECIAL_INITRD_FS_TARGET :
|
||||
mount_is_network(me) ? SPECIAL_REMOTE_FS_TARGET :
|
||||
SPECIAL_LOCAL_FS_TARGET;
|
||||
|
||||
k = add_mount(arg_dest,
|
||||
k = add_mount(fstab,
|
||||
arg_dest,
|
||||
what,
|
||||
canonical_where ?: where,
|
||||
canonical_where ? where: NULL,
|
||||
@@ -678,8 +697,7 @@ static int parse_fstab(bool initrd) {
|
||||
me->mnt_opts,
|
||||
me->mnt_passno,
|
||||
flags,
|
||||
post,
|
||||
fstab);
|
||||
target_unit);
|
||||
}
|
||||
|
||||
if (r >= 0 && k < 0)
|
||||
@@ -752,7 +770,7 @@ static int add_sysroot_mount(void) {
|
||||
}
|
||||
|
||||
if (streq(arg_root_what, "gpt-auto")) {
|
||||
/* This is handled by the gpt-auto generator */
|
||||
/* This is handled by gpt-auto-generator */
|
||||
log_debug("Skipping root directory handling, as gpt-auto was requested.");
|
||||
return 0;
|
||||
}
|
||||
@@ -818,7 +836,8 @@ static int add_sysroot_mount(void) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return add_mount(arg_dest,
|
||||
return add_mount("/proc/cmdline",
|
||||
arg_dest,
|
||||
what,
|
||||
"/sysroot",
|
||||
NULL,
|
||||
@@ -826,8 +845,7 @@ static int add_sysroot_mount(void) {
|
||||
opts,
|
||||
is_device_path(what) ? 1 : 0, /* passno */
|
||||
0, /* makefs off, growfs off, noauto off, nofail off, automount off */
|
||||
SPECIAL_INITRD_ROOT_FS_TARGET,
|
||||
"/proc/cmdline");
|
||||
SPECIAL_INITRD_ROOT_FS_TARGET);
|
||||
}
|
||||
|
||||
static int add_sysroot_usr_mount(void) {
|
||||
@@ -898,7 +916,8 @@ static int add_sysroot_usr_mount(void) {
|
||||
|
||||
log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what, strna(arg_usr_fstype), strempty(opts));
|
||||
|
||||
r = add_mount(arg_dest,
|
||||
r = add_mount("/proc/cmdline",
|
||||
arg_dest,
|
||||
what,
|
||||
"/sysusr/usr",
|
||||
NULL,
|
||||
@@ -906,14 +925,14 @@ static int add_sysroot_usr_mount(void) {
|
||||
opts,
|
||||
is_device_path(what) ? 1 : 0, /* passno */
|
||||
0,
|
||||
SPECIAL_INITRD_USR_FS_TARGET,
|
||||
"/proc/cmdline");
|
||||
SPECIAL_INITRD_USR_FS_TARGET);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_debug("Synthesizing entry what=/sysusr/usr where=/sysrootr/usr opts=bind");
|
||||
|
||||
r = add_mount(arg_dest,
|
||||
r = add_mount("/proc/cmdline",
|
||||
arg_dest,
|
||||
"/sysusr/usr",
|
||||
"/sysroot/usr",
|
||||
NULL,
|
||||
@@ -921,8 +940,7 @@ static int add_sysroot_usr_mount(void) {
|
||||
"bind",
|
||||
0,
|
||||
0,
|
||||
SPECIAL_INITRD_FS_TARGET,
|
||||
"/proc/cmdline");
|
||||
SPECIAL_INITRD_FS_TARGET);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -966,7 +984,8 @@ static int add_volatile_var(void) {
|
||||
|
||||
/* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
|
||||
|
||||
return add_mount(arg_dest_late,
|
||||
return add_mount("/proc/cmdline",
|
||||
arg_dest_late,
|
||||
"tmpfs",
|
||||
"/var",
|
||||
NULL,
|
||||
@@ -974,8 +993,7 @@ static int add_volatile_var(void) {
|
||||
"mode=0755" TMPFS_LIMITS_VAR,
|
||||
0,
|
||||
0,
|
||||
SPECIAL_LOCAL_FS_TARGET,
|
||||
"/proc/cmdline");
|
||||
SPECIAL_LOCAL_FS_TARGET);
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "string-util.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
static const char *arg_dest = "/tmp";
|
||||
static const char *arg_dest = NULL;
|
||||
static char *arg_resume_device = NULL;
|
||||
static char *arg_resume_options = NULL;
|
||||
static char *arg_root_options = NULL;
|
||||
@@ -109,17 +109,10 @@ static int process_resume(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
int r = 0;
|
||||
|
||||
log_setup_generator();
|
||||
|
||||
if (argc > 1 && argc != 4)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"This program takes three or no arguments.");
|
||||
|
||||
if (argc > 1)
|
||||
arg_dest = argv[1];
|
||||
arg_dest = ASSERT_PTR(dest);
|
||||
|
||||
/* Don't even consider resuming outside of initramfs. */
|
||||
if (!in_initrd()) {
|
||||
@@ -139,4 +132,4 @@ static int run(int argc, char *argv[]) {
|
||||
return process_resume();
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "macro.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "special.h"
|
||||
#include "specifier.h"
|
||||
#include "string-util.h"
|
||||
@@ -737,11 +738,15 @@ int generator_write_veritysetup_service_section(
|
||||
}
|
||||
|
||||
void log_setup_generator(void) {
|
||||
/* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
|
||||
if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */)
|
||||
log_set_prohibit_ipc(true);
|
||||
if (invoked_by_systemd()) {
|
||||
/* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
|
||||
if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */)
|
||||
log_set_prohibit_ipc(true);
|
||||
|
||||
/* This effectively means: journal for per-user generators, kmsg otherwise */
|
||||
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
|
||||
}
|
||||
|
||||
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); /* This effectively means: journal for per-user generators, kmsg otherwise */
|
||||
log_parse_environment();
|
||||
(void) log_open();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "main-func.h"
|
||||
|
||||
int generator_open_unit_file(
|
||||
@@ -86,11 +87,11 @@ void log_setup_generator(void);
|
||||
_DEFINE_MAIN_FUNCTION( \
|
||||
({ \
|
||||
log_setup_generator(); \
|
||||
if (argc > 1 && argc != 4) \
|
||||
if (!IN_SET(argc, 2, 4)) \
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), \
|
||||
"This program takes zero or three arguments."); \
|
||||
"This program takes one or three arguments."); \
|
||||
}), \
|
||||
impl(argc > 1 ? argv[1] : "/tmp", \
|
||||
argc > 1 ? argv[2] : "/tmp", \
|
||||
argc > 1 ? argv[3] : "/tmp"), \
|
||||
impl(argv[1], \
|
||||
argv[argc == 4 ? 2 : 1], \
|
||||
argv[argc == 4 ? 3 : 1]), \
|
||||
r < 0 ? EXIT_FAILURE : EXIT_SUCCESS)
|
||||
|
||||
@@ -49,9 +49,9 @@ static int start_default_target(sd_bus *bus) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
|
||||
log_info("Starting default target");
|
||||
log_info("Starting "SPECIAL_DEFAULT_TARGET);
|
||||
|
||||
/* Start these units only if we can replace base.target with it */
|
||||
/* Start this unit only if we can replace basic.target with it */
|
||||
r = sd_bus_call_method(bus,
|
||||
"org.freedesktop.systemd1",
|
||||
"/org/freedesktop/systemd1",
|
||||
@@ -62,7 +62,7 @@ static int start_default_target(sd_bus *bus) {
|
||||
"ss", SPECIAL_DEFAULT_TARGET, "isolate");
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
|
||||
return log_error_errno(r, "Failed to start "SPECIAL_DEFAULT_TARGET": %s", bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user