Merge pull request #2973 from poettering/search-path

Many fixes, in particular to the install logic
This commit is contained in:
Martin Pitt 2016-04-12 18:20:13 +02:00
commit 025ef1d226
99 changed files with 2438 additions and 2779 deletions

1
.gitignore vendored
View file

@ -249,7 +249,6 @@
/test-pty
/test-qcow2
/test-ratelimit
/test-rbtree
/test-replace-var
/test-resolve
/test-resolve-tables

View file

@ -213,6 +213,7 @@
b) socket() and socketpair() must get SOCK_CLOEXEC passed
c) recvmsg() must get MSG_CMSG_CLOEXEC set
d) F_DUPFD_CLOEXEC should be used instead of F_DUPFD, and so on
f) invocations of fopen() should take "e"
- We never use the POSIX version of basename() (which glibc defines it in
libgen.h), only the GNU version (which glibc defines in string.h).

View file

@ -747,8 +747,6 @@ libbasic_la_SOURCES = \
src/basic/missing_syscall.h \
src/basic/capability-util.c \
src/basic/capability-util.h \
src/basic/c-rbtree.c \
src/basic/c-rbtree.h \
src/basic/conf-files.c \
src/basic/conf-files.h \
src/basic/stdio-util.h \
@ -1038,7 +1036,9 @@ libshared_la_SOURCES = \
src/shared/machine-pool.c \
src/shared/machine-pool.h \
src/shared/resolve-util.c \
src/shared/resolve-util.h
src/shared/resolve-util.h \
src/shared/tests.h \
src/shared/tests.c
if HAVE_UTMP
libshared_la_SOURCES += \
@ -1494,7 +1494,6 @@ tests += \
test-copy \
test-cap-list \
test-sigbus \
test-rbtree \
test-verbs \
test-af-list \
test-arphrd-list \
@ -1748,12 +1747,6 @@ test_sigbus_SOURCES = \
test_sigbus_LDADD = \
libshared.la
test_rbtree_SOURCES = \
src/test/test-rbtree.c
test_rbtree_LDADD = \
libshared.la
test_condition_SOURCES = \
src/test/test-condition.c
@ -4729,8 +4722,7 @@ systemd_localed_SOURCES = \
src/locale/localed.c
systemd_localed_LDADD = \
libshared.la \
$(XKBCOMMON_LIBS)
libshared.la
systemd_localed_CFLAGS = \
$(AM_CFLAGS) \

3
NEWS
View file

@ -417,6 +417,9 @@ CHANGES WITH 228:
https://sourceware.org/bugzilla/show_bug.cgi?id=19108
Note that only util-linux versions built with
--enable-libmount-force-mountinfo are supported.
* Support for the ".snapshot" unit type has been removed. This
feature turned out to be little useful and little used, and
has now been removed from the core and from systemctl.

1
README
View file

@ -118,6 +118,7 @@ REQUIREMENTS:
glibc >= 2.16
libcap
libmount >= 2.27.1 (from util-linux)
(util-linux *must* be built with --enable-libmount-force-mountinfo)
libseccomp >= 1.0.0 (optional)
libblkid >= 2.24 (from util-linux) (optional)
libkmod >= 15 (optional)

25
TODO
View file

@ -33,16 +33,29 @@ Janitorial Clean-ups:
Features:
* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
* transient units: don't bother with actually setting unit properties, we
reload the unit file anyway
* machinectl remove --hidden + machinectl remove --all
* https://github.com/systemd/systemd/pull/2886 is fucked
* make sure resolved can be restarted without losing pushed-in dns config
* fix https://github.com/systemd/systemd/pull/2890, this shouldn't be exported
like this.
* journald: sigbus API via a signal-handler safe function that people may call
from the SIGBUS handler
* resolved: cefmz.x.incapdns.net fails to authenticate
* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
* move specifier expansion from service_spawn() into load-fragment.c
* optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
* resolved: maybe, after all, implement local listening for DNS packets on port
53.
127.0.0.53:53.
* delay activation of logind until somebody logs in, or when /dev/tty0 pulls it
in or lingering is on (so that containers don't bother with it until PAM is used). also exit-on-idle
@ -68,12 +81,6 @@ Features:
* push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy)
* add a new command "systemctl revert" or so, that removes all dropin
snippets in /run and /etc, and all unit files with counterparts in
/usr, and thus undoes what "systemctl set-property" and "systemctl
edit" create. Maybe even add "systemctl revert -a" to do this for
all units.
* PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn)
* consider throwing a warning if a service declares it wants to be "Before=" a .device unit.

View file

@ -133,7 +133,9 @@
<para>When listing VM or container images, do not suppress
images beginning in a dot character
(<literal>.</literal>).</para></listitem>
(<literal>.</literal>).</para>
<para>When cleaning VM or container images, remove all images, not just hidden ones.</para></listitem>
</varlistentry>
<varlistentry>
@ -217,9 +219,11 @@
<term><option>--read-only</option></term>
<listitem><para>When used with <command>bind</command>, applies
a read-only bind mount.</para></listitem>
</varlistentry>
a read-only bind mount.</para>
<para>When used with <command>clone</command>, <command>import-raw</command> or <command>import-tar</command> a
read-only container or VM image is created.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-n</option></term>
@ -599,7 +603,10 @@
all other settings that could identify the instance
unmodified. The original image and the cloned copy will hence
share these credentials, and it might be necessary to manually
change them in the copy.</para></listitem>
change them in the copy.</para>
<para>If combined with the <option>--read-only</option> switch a read-only cloned image is
created.</para></listitem>
</varlistentry>
<varlistentry>
@ -660,6 +667,23 @@
itself.</para></listitem>
</varlistentry>
<varlistentry>
<term><command>clean</command></term>
<listitem><para>Remove hidden VM or container images (or all). This command removes all hidden machine images
from <filename>/var/lib/machines</filename>, i.e. those whose name begins with a dot. Use <command>machinectl
list-images --all</command> to see a list of all machine images, including the hidden ones.</para>
<para>When combined with the <option>--all</option> switch removes all images, not just hidden ones. This
command effectively empties <filename>/var/lib/machines</filename>.</para>
<para>Note that commands such as <command>machinectl pull-tar</command> or <command>machinectl
pull-raw</command> usually create hidden, read-only, unmodified machine images from the downloaded image first,
before cloning a writable working copy of it, in order to avoid duplicate downloads in case of images that are
reused multiple times. Use <command>machinectl clean</command> to remove old, hidden images created this
way.</para></listitem>
</varlistentry>
</variablelist></refsect2>
<refsect2><title>Image Transfer Commands</title><variablelist>

View file

@ -1168,22 +1168,32 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</row>
<row>
<entry><literal>static</literal></entry>
<entry>The unit file is not enabled, and has no provisions for enabling in the <literal>[Install]</literal> section.</entry>
<entry>The unit file is not enabled, and has no provisions for enabling in the <literal>[Install]</literal> unit file section.</entry>
<entry>0</entry>
</row>
<row>
<entry><literal>indirect</literal></entry>
<entry>The unit file itself is not enabled, but it has a non-empty <varname>Also=</varname> setting in the <literal>[Install]</literal> section, listing other unit files that might be enabled.</entry>
<entry>The unit file itself is not enabled, but it has a non-empty <varname>Also=</varname> setting in the <literal>[Install]</literal> unit file section, listing other unit files that might be enabled.</entry>
<entry>0</entry>
</row>
<row>
<entry><literal>disabled</literal></entry>
<entry>Unit file is not enabled, but contains an <literal>[Install]</literal> section with installation instructions.</entry>
<entry>The unit file is not enabled, but contains an <literal>[Install]</literal> section with installation instructions.</entry>
<entry>&gt; 0</entry>
</row>
<row>
<entry><literal>generated</literal></entry>
<entry>The unit file was generated dynamically via a generator tool. See <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>. Generated unit files may not be enabled, they are enabled implicitly by their generator.</entry>
<entry>0</entry>
</row>
<row>
<entry><literal>transient</literal></entry>
<entry>The unit file has been created dynamically with the runtime API. Transient units may not be enabled.</entry>
<entry>0</entry>
</row>
<row>
<entry><literal>bad</literal></entry>
<entry>Unit file is invalid or another error occurred. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry>
<entry>The unit file is invalid or another error occurred. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry>
<entry>&gt; 0</entry>
</row>
</tbody>
@ -1234,6 +1244,28 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</listitem>
</varlistentry>
<varlistentry>
<term><command>revert <replaceable>NAME</replaceable>...</command></term>
<listitem>
<para>Revert one or more unit files to their vendor versions. This command removes drop-in configuration
files that modify the specified units, as well as any user-configured unit file that overrides a matching
vendor supplied unit file. Specifically, for a unit <literal>foo.service</literal> the matching directories
<literal>foo.service.d/</literal> with all their contained files are removed, both below the persistent and
runtime configuration directories (i.e. below <filename>/etc/systemd/system</filename> and
<filename>/run/systemd/system</filename>); if the unit file has a vendor-supplied version (i.e. a unit file
located below <filename>/usr</filename>) any matching peristent or runtime unit file that overrides it is
removed, too. Note that if a unit file has no vendor-supplied version (i.e. is only defined below
<filename>/etc/systemd/system</filename> or <filename>/run/systemd/system</filename>, but not in a unit
file stored below <filename>/usr</filename>), then it is not removed. Also, if a unit is masked, it is
unmasked.</para>
<para>Effectively, this command may be used to undo all changes made with <command>systemctl
edit</command>, <command>systemctl set-property</command> and <command>systemctl mask</command> and puts
the original unit file with its settings back in effect.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>add-wants <replaceable>TARGET</replaceable>
<replaceable>NAME</replaceable>...</command></term>

View file

@ -58,7 +58,7 @@
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-nspawn</command>
<arg choice="plain">-b</arg>
<arg choice="plain">--boot</arg>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">ARGS</arg>
</cmdsynopsis>
@ -263,7 +263,7 @@
signals. It is recommended to use this mode to invoke arbitrary commands in containers, unless they have been
modified to run correctly as PID 1. Or in other words: this switch should be used for pretty much all commands,
except when the command refers to an init or shell implementation, as these are generally capable of running
correctly as PID 1). This option may not be combined with <option>--boot</option> or
correctly as PID 1. This option may not be combined with <option>--boot</option> or
<option>--share-system</option>.</para>
</listitem>
</varlistentry>
@ -294,12 +294,12 @@
<tbody>
<row>
<entry>Neither <option>--as-pid2</option> nor <option>--boot</option> specified</entry>
<entry>The passed parameters are interpreted as command line, which is executed as PID 1 in the container.</entry>
<entry>The passed parameters are interpreted as the command line, which is executed as PID 1 in the container.</entry>
</row>
<row>
<entry><option>--as-pid2</option> specified</entry>
<entry>The passed parameters are interpreted as command line, which are executed as PID 2 in the container. A stub init process is run as PID 1.</entry>
<entry>The passed parameters are interpreted as the command line, which is executed as PID 2 in the container. A stub init process is run as PID 1.</entry>
</row>
<row>

View file

@ -97,11 +97,9 @@
<para>An implicit <varname>Before=</varname> dependency is created
between an automount unit and the mount unit it activates.</para>
<para>Automount units acquire automatic <varname>Before=</varname>
and <varname>Conflicts=</varname> on
<filename>umount.target</filename> in order to be stopped during
shutdown, unless <varname>DefaultDependencies=no</varname> is
set.</para>
<para>Automount units acquire automatic <varname>Before=</varname> and <varname>Conflicts=</varname> on
<filename>umount.target</filename> in order to be stopped during shutdown, unless
<varname>DefaultDependencies=no</varname> is set in the <literal>[Unit]</literal> section.</para>
</refsect1>

View file

@ -128,26 +128,17 @@
<filename>systemd-quotacheck.service</filename> and
<filename>quotaon.service</filename> are added.</para>
<para>For mount units with
<varname>DefaultDependencies=yes</varname> (the default) a couple
additional dependencies are added. Mount units referring to local
file systems automatically gain an <varname>After=</varname>
dependency on <filename>local-fs-pre.target</filename>. Network
mount units automatically acquire <varname>After=</varname>
dependencies on <filename>remote-fs-pre.target</filename>,
<filename>network.target</filename> and
<filename>network-online.target</filename>. Towards the latter a
<varname>Wants=</varname> unit is added as well. Mount units
referring to local and network file systems are distinguished by
their file system type specification. In some cases this is not
sufficient (for example network block device based mounts, such as
iSCSI), in which case <option>_netdev</option> may be added to the
mount option string of the unit, which forces systemd to consider the
mount unit a network mount. Mount units (regardless if local or
network) also acquire automatic <varname>Before=</varname> and
<varname>Conflicts=</varname> on
<filename>umount.target</filename> in order to be stopped
during shutdown.</para>
<para>For mount units with <varname>DefaultDependencies=yes</varname> in the <literal>[Unit]</literal> section (the
default) a couple additional dependencies are added. Mount units referring to local file systems automatically gain
an <varname>After=</varname> dependency on <filename>local-fs-pre.target</filename>. Network mount units
automatically acquire <varname>After=</varname> dependencies on <filename>remote-fs-pre.target</filename>,
<filename>network.target</filename> and <filename>network-online.target</filename>. Towards the latter a
<varname>Wants=</varname> unit is added as well. Mount units referring to local and network file systems are
distinguished by their file system type specification. In some cases this is not sufficient (for example network
block device based mounts, such as iSCSI), in which case <option>_netdev</option> may be added to the mount option
string of the unit, which forces systemd to consider the mount unit a network mount. Mount units (regardless if
local or network) also acquire automatic <varname>Before=</varname> and <varname>Conflicts=</varname> on
<filename>umount.target</filename> in order to be stopped during shutdown.</para>
<para>Additional implicit dependencies may be added as result of
execution and resource control parameters as documented in

View file

@ -91,16 +91,12 @@
<para>An implicit <varname>Before=</varname> dependency is added
between a path unit and the unit it is supposed to activate.</para>
<para>Unless <varname>DefaultDependencies=false</varname> is used,
path units will implicitly have dependencies of type
<varname>Before=</varname> on <filename>paths.target</filename>,
dependencies of type <varname>After=</varname> and
<varname>Requires=</varname> on
<filename>sysinit.target</filename>, and have dependencies of type
<varname>Conflicts=</varname> and <varname>Before=</varname> on
<filename>shutdown.target</filename>. These ensure that path units
are terminated cleanly prior to system shutdown. Only path units
involved with early boot or late system shutdown should disable
<para>Unless <varname>DefaultDependencies=false</varname> in the <literal>[Unit]</literal> section is used, path
units will implicitly have dependencies of type <varname>Before=</varname> on <filename>paths.target</filename>,
dependencies of type <varname>After=</varname> and <varname>Requires=</varname> on
<filename>sysinit.target</filename>, and have dependencies of type <varname>Conflicts=</varname> and
<varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure that path units are terminated
cleanly prior to system shutdown. Only path units involved with early boot or late system shutdown should disable
this option.
</para>
</refsect1>

View file

@ -100,18 +100,13 @@
their activated <filename>.socket</filename> units via an
automatic <varname>After=</varname> dependency.</para>
<para>Unless <varname>DefaultDependencies=</varname> is set to
<option>false</option>, service units will implicitly have
dependencies of type <varname>Requires=</varname> and
<varname>After=</varname> on <filename>sysinit.target</filename>,
a dependency of type <varname>After=</varname> on
<filename>basic.target</filename> as well as dependencies of
type <varname>Conflicts=</varname> and <varname>Before=</varname>
on <filename>shutdown.target</filename>. These ensure that normal
service units pull in basic system initialization, and are
terminated cleanly prior to system shutdown. Only services
involved with early boot or late system shutdown should disable
this option.</para>
<para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> is set to
<option>false</option>, service units will implicitly have dependencies of type <varname>Requires=</varname> and
<varname>After=</varname> on <filename>sysinit.target</filename>, a dependency of type <varname>After=</varname> on
<filename>basic.target</filename> as well as dependencies of type <varname>Conflicts=</varname> and
<varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure that normal service units pull in
basic system initialization, and are terminated cleanly prior to system shutdown. Only services involved with early
boot or late system shutdown should disable this option.</para>
<para>Instanced service units (i.e. service units with an <literal>@</literal> in their name) are assigned by
default a per-template slice unit (see

View file

@ -106,14 +106,10 @@
<varname>After=</varname> and <varname>Requires=</varname> on
their immediate parent slice unit.</para>
<para>Unless <varname>DefaultDependencies=false</varname>
is used, slice units will implicitly have dependencies of
type <varname>Conflicts=</varname> and
<varname>Before=</varname> on
<filename>shutdown.target</filename>. These ensure
that slice units are removed prior to system
shutdown. Only slice units involved with early boot or
late system shutdown should disable this option.
<para>Unless <varname>DefaultDependencies=false</varname> is used in the <literal>[Unit]</literal> section, slice
units will implicitly have dependencies of type <varname>Conflicts=</varname> and <varname>Before=</varname> on
<filename>shutdown.target</filename>. These ensure that slice units are removed prior to system shutdown. Only
slice units involved with early boot or late system shutdown should disable this option.
</para>
</refsect1>

View file

@ -97,16 +97,12 @@
<filename>foo@.service</filename> must exist from which services
are instantiated for each incoming connection.</para>
<para>Unless <varname>DefaultDependencies=</varname> is set to
<option>false</option>, socket units will implicitly have
dependencies of type <varname>Requires=</varname> and
<varname>After=</varname> on <filename>sysinit.target</filename>
as well as dependencies of type <varname>Conflicts=</varname> and
<varname>Before=</varname> on
<filename>shutdown.target</filename>. These ensure that socket
units pull in basic system initialization, and are terminated
cleanly prior to system shutdown. Only sockets involved with early
boot or late system shutdown should disable this option.</para>
<para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
<option>false</option>, socket units will implicitly have dependencies of type <varname>Requires=</varname> and
<varname>After=</varname> on <filename>sysinit.target</filename> as well as dependencies of type
<varname>Conflicts=</varname> and <varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure
that socket units pull in basic system initialization, and are terminated cleanly prior to system shutdown. Only
sockets involved with early boot or late system shutdown should disable this option.</para>
<para>Socket units will have a <varname>Before=</varname>
dependency on the service which they trigger added implicitly. No

View file

@ -95,12 +95,10 @@
dependencies on the device units or the mount units of the files
they are activated from.</para>
<para>Swap units with <varname>DefaultDependencies=</varname>
enabled implicitly acquire a <varname>Conflicts=</varname> and an
<varname>After=</varname> dependency on
<filename>umount.target</filename> so that they are deactivated at
shutdown, unless <varname>DefaultDependencies=no</varname> is
specified.</para>
<para>Swap units with <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section enabled
implicitly acquire a <varname>Conflicts=</varname> and an <varname>After=</varname> dependency on
<filename>umount.target</filename> so that they are deactivated at shutdown, unless
<varname>DefaultDependencies=no</varname> is specified.</para>
<para>Additional implicit dependencies may be added as result of
execution and resource control parameters as documented in

View file

@ -82,14 +82,11 @@
<refsect1>
<title>Automatic Dependencies</title>
<para>Unless <varname>DefaultDependencies=</varname> is set to
<option>no</option>, target units will implicitly complement all
configured dependencies of type <varname>Wants=</varname>,
<varname>Requires=</varname> with dependencies of type
<varname>After=</varname>, unless an ordering dependency of any
kind between the target and the respective other unit is already
in place. Note that this behaviour is disabled if either unit has
<varname>DefaultDependencies=no</varname>.</para>
<para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
<option>no</option>, target units will implicitly complement all configured dependencies of type
<varname>Wants=</varname>, <varname>Requires=</varname> with dependencies of type <varname>After=</varname>, unless
an ordering dependency of any kind between the target and the respective other unit is already in place. Note that
this behaviour is disabled if either unit has <varname>DefaultDependencies=no</varname>.</para>
</refsect1>
<refsect1>

View file

@ -81,21 +81,15 @@
<para>Timer units automatically gain a <varname>Before=</varname>
dependency on the service they are supposed to activate.</para>
<para>Unless <varname>DefaultDependencies=</varname> is set to
<option>false</option>, all timer units will implicitly have
dependencies of type <varname>Requires=</varname> and
<varname>After=</varname> on <filename>sysinit.target</filename>,
a dependency of type <varname>Before=</varname> on
<filename>timers.target</filename>, as well as
<varname>Conflicts=</varname> and <varname>Before=</varname> on
<filename>shutdown.target</filename> to ensure that they are
stopped cleanly prior to system shutdown. Timer units with at
least one <varname>OnCalendar=</varname> directive will have an
additional <varname>After=</varname> dependency on
<filename>timer-sync.target</filename> to avoid being started
before the system clock has been correctly set. Only timer units
involved with early boot or late system shutdown should disable
the <varname>DefaultDependencies=</varname> option.</para>
<para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
<option>false</option>, all timer units will implicitly have dependencies of type <varname>Requires=</varname> and
<varname>After=</varname> on <filename>sysinit.target</filename>, a dependency of type <varname>Before=</varname>
on <filename>timers.target</filename>, as well as <varname>Conflicts=</varname> and <varname>Before=</varname> on
<filename>shutdown.target</filename> to ensure that they are stopped cleanly prior to system shutdown. Timer units
with at least one <varname>OnCalendar=</varname> directive will have an additional <varname>After=</varname>
dependency on <filename>timer-sync.target</filename> to avoid being started before the system clock has been
correctly set. Only timer units involved with early boot or late system shutdown should disable the
<varname>DefaultDependencies=</varname> option.</para>
</refsect1>
<refsect1>

View file

@ -66,18 +66,16 @@
<para><literallayout><filename>/etc/systemd/system/*</filename>
<filename>/run/systemd/system/*</filename>
<filename>/usr/lib/systemd/system/*</filename>
<filename>...</filename>
<filename></filename>
</literallayout></para>
<para><literallayout><filename>$XDG_CONFIG_HOME/systemd/user/*</filename>
<filename>$HOME/.config/systemd/user/*</filename>
<para><literallayout><filename>~/.config/systemd/user/*</filename>
<filename>/etc/systemd/user/*</filename>
<filename>$XDG_RUNTIME_DIR/systemd/user/*</filename>
<filename>/run/systemd/user/*</filename>
<filename>$XDG_DATA_HOME/systemd/user/*</filename>
<filename>$HOME/.local/share/systemd/user/*</filename>
<filename>~/.local/share/systemd/user/*</filename>
<filename>/usr/lib/systemd/user/*</filename>
<filename>...</filename>
<filename></filename>
</literallayout></para>
</refsynopsisdiv>

View file

@ -231,14 +231,12 @@ static int verify_unit(Unit *u, bool check_man) {
return r;
}
int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
int verify_units(char **filenames, UnitFileScope scope, bool check_man) {
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *var = NULL;
Manager *m = NULL;
FILE *serial = NULL;
FDSet *fdset = NULL;
_cleanup_free_ char *var = NULL;
char **filename;
int r = 0, k;
@ -255,7 +253,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man)
assert_se(set_unit_path(var) >= 0);
r = manager_new(running_as, true, &m);
r = manager_new(scope, true, &m);
if (r < 0)
return log_error_errno(r, "Failed to initialize manager: %m");

View file

@ -23,4 +23,4 @@
#include "path-lookup.h"
int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man);
int verify_units(char **filenames, UnitFileScope scope, bool check_man);

View file

@ -1443,7 +1443,7 @@ int main(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "verify"))
r = verify_units(argv+optind+1,
arg_user ? MANAGER_USER : MANAGER_SYSTEM,
arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
arg_man);
else {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;

View file

@ -1,674 +0,0 @@
/***
This file is part of systemd. See COPYING for details.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* RB-Tree Implementation
* This implements the insertion/removal of elements in RB-Trees. You're highly
* recommended to have an RB-Tree documentation at hand when reading this. Both
* insertion and removal can be split into a handful of situations that can
* occur. Those situations are enumerated as "Case 1" to "Case n" here, and
* follow closely the cases described in most RB-Tree documentations. This file
* does not explain why it is enough to handle just those cases, nor does it
* provide a proof of correctness. Dig out your algorithm 101 handbook if
* you're interested.
*
* This implementation is *not* straightforward. Usually, a handful of
* rotation, reparent, swap and link helpers can be used to implement the
* rebalance operations. However, those often perform unnecessary writes.
* Therefore, this implementation hard-codes all the operations. You're highly
* recommended to look at the two basic helpers before reading the code:
* c_rbtree_swap_child()
* c_rbtree_set_parent_and_color()
* Those are the only helpers used, hence, you should really know what they do
* before digging into the code.
*
* For a highlevel documentation of the API, see the header file and docbook
* comments.
*/
#include <assert.h>
#include <stddef.h>
#include "c-rbtree.h"
enum {
C_RBNODE_RED = 0,
C_RBNODE_BLACK = 1,
};
static inline unsigned long c_rbnode_color(CRBNode *n) {
return (unsigned long)n->__parent_and_color & 1UL;
}
static inline _Bool c_rbnode_is_red(CRBNode *n) {
return c_rbnode_color(n) == C_RBNODE_RED;
}
static inline _Bool c_rbnode_is_black(CRBNode *n) {
return c_rbnode_color(n) == C_RBNODE_BLACK;
}
/**
* c_rbnode_leftmost() - return leftmost child
* @n: current node, or NULL
*
* This returns the leftmost child of @n. If @n is NULL, this will return NULL.
* In all other cases, this function returns a valid pointer. That is, if @n
* does not have any left children, this returns @n.
*
* Worst case runtime (n: number of elements in tree): O(log(n))
*
* Return: Pointer to leftmost child, or NULL.
*/
CRBNode *c_rbnode_leftmost(CRBNode *n) {
if (n)
while (n->left)
n = n->left;
return n;
}
/**
* c_rbnode_rightmost() - return rightmost child
* @n: current node, or NULL
*
* This returns the rightmost child of @n. If @n is NULL, this will return
* NULL. In all other cases, this function returns a valid pointer. That is, if
* @n does not have any right children, this returns @n.
*
* Worst case runtime (n: number of elements in tree): O(log(n))
*
* Return: Pointer to rightmost child, or NULL.
*/
CRBNode *c_rbnode_rightmost(CRBNode *n) {
if (n)
while (n->right)
n = n->right;
return n;
}
/**
* c_rbnode_next() - return next node
* @n: current node, or NULL
*
* An RB-Tree always defines a linear order of its elements. This function
* returns the logically next node to @n. If @n is NULL, the last node or
* unlinked, this returns NULL.
*
* Worst case runtime (n: number of elements in tree): O(log(n))
*
* Return: Pointer to next node, or NULL.
*/
CRBNode *c_rbnode_next(CRBNode *n) {
CRBNode *p;
if (!c_rbnode_is_linked(n))
return NULL;
if (n->right)
return c_rbnode_leftmost(n->right);
while ((p = c_rbnode_parent(n)) && n == p->right)
n = p;
return p;
}
/**
* c_rbnode_prev() - return previous node
* @n: current node, or NULL
*
* An RB-Tree always defines a linear order of its elements. This function
* returns the logically previous node to @n. If @n is NULL, the first node or
* unlinked, this returns NULL.
*
* Worst case runtime (n: number of elements in tree): O(log(n))
*
* Return: Pointer to previous node, or NULL.
*/
CRBNode *c_rbnode_prev(CRBNode *n) {
CRBNode *p;
if (!c_rbnode_is_linked(n))
return NULL;
if (n->left)
return c_rbnode_rightmost(n->left);
while ((p = c_rbnode_parent(n)) && n == p->left)
n = p;
return p;
}
/**
* c_rbtree_first() - return first node
* @t: tree to operate on
*
* An RB-Tree always defines a linear order of its elements. This function
* returns the logically first node in @t. If @t is empty, NULL is returned.
*
* Fixed runtime (n: number of elements in tree): O(log(n))
*
* Return: Pointer to first node, or NULL.
*/
CRBNode *c_rbtree_first(CRBTree *t) {
assert(t);
return c_rbnode_leftmost(t->root);
}
/**
* c_rbtree_last() - return last node
* @t: tree to operate on
*
* An RB-Tree always defines a linear order of its elements. This function
* returns the logically last node in @t. If @t is empty, NULL is returned.
*
* Fixed runtime (n: number of elements in tree): O(log(n))
*
* Return: Pointer to last node, or NULL.
*/
CRBNode *c_rbtree_last(CRBTree *t) {
assert(t);
return c_rbnode_rightmost(t->root);
}
/*
* Set the color and parent of a node. This should be treated as a simple
* assignment of the 'color' and 'parent' fields of the node. No other magic is
* applied. But since both fields share its backing memory, this helper
* function is provided.
*/
static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) {
assert(!((unsigned long)p & 1));
assert(c < 2);
n->__parent_and_color = (CRBNode*)((unsigned long)p | c);
}
/* same as c_rbnode_set_parent_and_color(), but keeps the current color */
static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) {
c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n));
}
/*
* This function partially replaces an existing child pointer to a new one. The
* existing child must be given as @old, the new child as @new. @p must be the
* parent of @old (or NULL if it has no parent).
* This function ensures that the parent of @old now points to @new. However,
* it does *NOT* change the parent pointer of @new. The caller must ensure
* this.
* If @p is NULL, this function ensures that the root-pointer is adjusted
* instead (given as @t).
*/
static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) {
if (p) {
if (p->left == old)
p->left = new;
else
p->right = new;
} else {
t->root = new;
}
}
static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) {
CRBNode *p, *g, *gg, *u, *x;
/*
* Paint a single node according to RB-Tree rules. The node must
* already be linked into the tree and painted red.
* We repaint the node or rotate the tree, if required. In case a
* recursive repaint is required, the next node to be re-painted
* is returned.
* p: parent
* g: grandparent
* gg: grandgrandparent
* u: uncle
* x: temporary
*/
/* node is red, so we can access the parent directly */
p = n->__parent_and_color;
if (!p) {
/* Case 1:
* We reached the root. Mark it black and be done. As all
* leaf-paths share the root, the ratio of black nodes on each
* path stays the same. */
c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK);
n = NULL;
} else if (c_rbnode_is_black(p)) {
/* Case 2:
* The parent is already black. As our node is red, we did not
* change the number of black nodes on any path, nor do we have
* multiple consecutive red nodes. */
n = NULL;
} else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */
g = p->__parent_and_color;
gg = c_rbnode_parent(g);
u = g->right;
if (u && c_rbnode_is_red(u)) {
/* Case 3:
* Parent and uncle are both red. We know the
* grandparent must be black then. Repaint parent and
* uncle black, the grandparent red and recurse into
* the grandparent. */
c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED);
n = g;
} else {
/* parent is red, uncle is black */
if (n == p->right) {
/* Case 4:
* We're the right child. Rotate on parent to
* become left child, so we can handle it the
* same as case 5. */
x = n->left;
p->right = n->left;
n->left = p;
if (x)
c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED);
p = n;
}
/* 'n' is invalid from here on! */
n = NULL;
/* Case 5:
* We're the red left child or a red parent, black
* grandparent and uncle. Rotate on grandparent and
* switch color with parent. Number of black nodes on
* each path stays the same, but we got rid of the
* double red path. As the grandparent is still black,
* we're done. */
x = p->right;
g->left = x;
p->right = g;
if (x)
c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED);
c_rbtree_swap_child(t, gg, g, p);
}
} else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */
g = p->__parent_and_color;
gg = c_rbnode_parent(g);
u = g->left;
if (u && c_rbnode_is_red(u)) {
c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED);
n = g;
} else {
if (n == p->left) {
x = n->right;
p->left = n->right;
n->right = p;
if (x)
c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED);
p = n;
}
n = NULL;
x = p->left;
g->right = x;
p->left = g;
if (x)
c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED);
c_rbtree_swap_child(t, gg, g, p);
}
}
return n;
}
static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) {
assert(t);
assert(n);
while (n)
n = c_rbtree_paint_one(t, n);
}
/**
* c_rbtree_add() - add node to tree
* @t: tree to operate one
* @p: parent node to link under, or NULL
* @l: left/right slot of @p (or root) to link at
* @n: node to add
*
* This links @n into the tree given as @t. The caller must provide the exact
* spot where to link the node. That is, the caller must traverse the tree
* based on their search order. Once they hit a leaf where to insert the node,
* call this function to link it and rebalance the tree.
*
* A typical insertion would look like this (@t is your tree, @n is your node):
*
* CRBNode **i, *p;
*
* i = &t->root;
* p = NULL;
* while (*i) {
* p = *i;
* if (compare(n, *i) < 0)
* i = &(*i)->left;
* else
* i = &(*i)->right;
* }
*
* c_rbtree_add(t, p, i, n);
*
* Once the node is linked into the tree, a simple lookup on the same tree can
* be coded like this:
*
* CRBNode *i;
*
* i = t->root;
* while (i) {
* int v = compare(n, i);
* if (v < 0)
* i = (*i)->left;
* else if (v > 0)
* i = (*i)->right;
* else
* break;
* }
*
* When you add nodes to a tree, the memory contents of the node do not matter.
* That is, there is no need to initialize the node via c_rbnode_init().
* However, if you relink nodes multiple times during their lifetime, it is
* usually very convenient to use c_rbnode_init() and c_rbtree_remove_init().
* In those cases, you should validate that a node is unlinked before you call
* c_rbtree_add().
*/
void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) {
assert(t);
assert(l);
assert(n);
assert(!p || l == &p->left || l == &p->right);
assert(p || l == &t->root);
c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED);
n->left = n->right = NULL;
*l = n;
c_rbtree_paint(t, n);
}
static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) {
CRBNode *s, *x, *y, *g;
/*
* Rebalance tree after a node was removed. This happens only if you
* remove a black node and one path is now left with an unbalanced
* number or black nodes.
* This function assumes all paths through p and n have one black node
* less than all other paths. If recursive fixup is required, the
* current node is returned.
*/
if (n == p->left) {
s = p->right;
if (c_rbnode_is_red(s)) {
/* Case 3:
* We have a red node as sibling. Rotate it onto our
* side so we can later on turn it black. This way, we
* gain the additional black node in our path. */
g = c_rbnode_parent(p);
x = s->left;
p->right = x;
s->left = p;
c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED);
c_rbtree_swap_child(t, g, p, s);
s = x;
}
x = s->right;
if (!x || c_rbnode_is_black(x)) {
y = s->left;
if (!y || c_rbnode_is_black(y)) {
/* Case 4:
* Our sibling is black and has only black
* children. Flip it red and turn parent black.
* This way we gained a black node in our path,
* or we fix it recursively one layer up, which
* will rotate the red sibling as parent. */
c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED);
if (c_rbnode_is_black(p))
return p;
c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK);
return NULL;
}
/* Case 5:
* Left child of our sibling is red, right one is black.
* Rotate on parent so the right child of our sibling is
* now red, and we can fall through to case 6. */
x = y->right;
s->left = y->right;
y->right = s;
p->right = y;
if (x)
c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
x = s;
s = y;
}
/* Case 6:
* The right child of our sibling is red. Rotate left and flip
* colors, which gains us an additional black node in our path,
* that was previously on our sibling. */
g = c_rbnode_parent(p);
y = s->left;
p->right = y;
s->left = p;
c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
if (y)
c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y));
c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK);
c_rbtree_swap_child(t, g, p, s);
} else /* if (!n || n == p->right) */ { /* same as above, but mirrored */
s = p->left;
if (c_rbnode_is_red(s)) {
g = c_rbnode_parent(p);
x = s->right;
p->left = x;
s->right = p;
c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK);
c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED);
c_rbtree_swap_child(t, g, p, s);
s = x;
}
x = s->left;
if (!x || c_rbnode_is_black(x)) {
y = s->right;
if (!y || c_rbnode_is_black(y)) {
c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED);
if (c_rbnode_is_black(p))
return p;
c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK);
return NULL;
}
x = y->left;
s->right = y->left;
y->left = s;
p->left = y;
if (x)
c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
x = s;
s = y;
}
g = c_rbnode_parent(p);
y = s->right;
p->left = y;
s->right = p;
c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
if (y)
c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y));
c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK);
c_rbtree_swap_child(t, g, p, s);
}
return NULL;
}
static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) {
CRBNode *n = NULL;
assert(t);
assert(p);
do {
n = c_rbtree_rebalance_one(t, p, n);
p = n ? c_rbnode_parent(n) : NULL;
} while (p);
}
/**
* c_rbtree_remove() - remove node from tree
* @t: tree to operate one
* @n: node to remove
*
* This removes the given node from its tree. Once unlinked, the tree is
* rebalanced.
* The caller *must* ensure that the given tree is actually the tree it is
* linked on. Otherwise, behavior is undefined.
*
* This does *NOT* reset @n to being unlinked (for performance reason, this
* function *never* modifies @n at all). If you need this, use
* c_rbtree_remove_init().
*/
void c_rbtree_remove(CRBTree *t, CRBNode *n) {
CRBNode *p, *s, *gc, *x, *next = NULL;
unsigned long c;
assert(t);
assert(n);
assert(c_rbnode_is_linked(n));
/*
* There are three distinct cases during node removal of a tree:
* * The node has no children, in which case it can simply be removed.
* * The node has exactly one child, in which case the child displaces
* its parent.
* * The node has two children, in which case there is guaranteed to
* be a successor to the node (successor being the node ordered
* directly after it). This successor cannot have two children by
* itself (two interior nodes can never be successive). Therefore,
* we can simply swap the node with its successor (including color)
* and have reduced this case to either of the first two.
*
* Whenever the node we removed was black, we have to rebalance the
* tree. Note that this affects the actual node we _remove_, not @n (in
* case we swap it).
*
* p: parent
* s: successor
* gc: grand-...-child
* x: temporary
* next: next node to rebalance on
*/
if (!n->left) {
/*
* Case 1:
* The node has no left child. If it neither has a right child,
* it is a leaf-node and we can simply unlink it. If it also
* was black, we have to rebalance, as always if we remove a
* black node.
* But if the node has a right child, the child *must* be red
* (otherwise, the right path has more black nodes as the
* non-existing left path), and the node to be removed must
* hence be black. We simply replace the node with its child,
* turning the red child black, and thus no rebalancing is
* required.
*/
p = c_rbnode_parent(n);
c = c_rbnode_color(n);
c_rbtree_swap_child(t, p, n, n->right);
if (n->right)
c_rbnode_set_parent_and_color(n->right, p, c);
else
next = (c == C_RBNODE_BLACK) ? p : NULL;
} else if (!n->right) {
/*
* Case 1.1:
* The node has exactly one child, and it is on the left. Treat
* it as mirrored case of Case 1 (i.e., replace the node by its
* child).
*/
p = c_rbnode_parent(n);
c = c_rbnode_color(n);
c_rbtree_swap_child(t, p, n, n->left);
c_rbnode_set_parent_and_color(n->left, p, c);
} else {
/*
* Case 2:
* We are dealing with a full interior node with a child not on
* both sides. Find its successor and swap it. Then remove the
* node similar to Case 1. For performance reasons we don't
* perform the full swap, but skip links that are about to be
* removed, anyway.
*/
s = n->right;
if (!s->left) {
/* right child is next, no need to touch grandchild */
p = s;
gc = s->right;
} else {
/* find successor and swap partially */
s = c_rbnode_leftmost(s);
p = c_rbnode_parent(s);
gc = s->right;
p->left = s->right;
s->right = n->right;
c_rbnode_set_parent(n->right, s);
}
/* node is partially swapped, now remove as in Case 1 */
s->left = n->left;
c_rbnode_set_parent(n->left, s);
x = c_rbnode_parent(n);
c = c_rbnode_color(n);
c_rbtree_swap_child(t, x, n, s);
if (gc)
c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK);
else
next = c_rbnode_is_black(s) ? p : NULL;
c_rbnode_set_parent_and_color(s, x, c);
}
if (next)
c_rbtree_rebalance(t, next);
}

View file

@ -1,297 +0,0 @@
#pragma once
/***
This file is part of systemd. See COPYING for details.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* Standalone Red-Black-Tree Implementation in Standard ISO-C11
*
* This header provides an RB-Tree API, that is fully implemented in ISO-C11
* and has no external dependencies. Furthermore, tree traversal, memory
* allocations, and key comparisons a fully in control of the API user. The
* implementation only provides the RB-Tree specific rebalancing and coloring.
*
* A tree is represented by the "CRBTree" structure. It contains a *singly*
* field, which is a pointer to the root node. If NULL, the tree is empty. If
* non-NULL, there is at least a single element in the tree.
*
* Each node of the tree is represented by the "CRBNode" structure. It has
* three fields. The @left and @right members can be accessed by the API user
* directly to traverse the tree. The third member is an implementation detail
* and encodes the parent pointer and color of the node.
* API users are required to embed the CRBNode object into their own objects
* and then use offsetof() (i.e., container_of() and friends) to turn CRBNode
* pointers into pointers to their own structure.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct CRBNode CRBNode;
typedef struct CRBTree CRBTree;
/**
* struct CRBNode - Node of a Red-Black Tree
* @__parent_and_color: internal state
* @left: left child, or NULL
* @right: right child, or NULL
*
* Each node in an RB-Tree must embed an CRBNode object. This object contains
* pointers to its left and right child, which can be freely accessed by the
* API user at any time. They are NULL, if the node does not have a left/right
* child.
*
* The @__parent_and_color field must never be accessed directly. It encodes
* the pointer to the parent node, and the color of the node. Use the accessor
* functions instead.
*
* There is no reason to initialize a CRBNode object before linking it.
* However, if you need a boolean state that tells you whether the node is
* linked or not, you should initialize the node via c_rbnode_init() or
* C_RBNODE_INIT.
*/
struct CRBNode {
CRBNode *__parent_and_color;
CRBNode *left;
CRBNode *right;
};
#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) }
CRBNode *c_rbnode_leftmost(CRBNode *n);
CRBNode *c_rbnode_rightmost(CRBNode *n);
CRBNode *c_rbnode_next(CRBNode *n);
CRBNode *c_rbnode_prev(CRBNode *n);
/**
* struct CRBTree - Red-Black Tree
* @root: pointer to the root node, or NULL
*
* Each Red-Black Tree is rooted in an CRBTree object. This object contains a
* pointer to the root node of the tree. The API user is free to access the
* @root member at any time, and use it to traverse the tree.
*
* To initialize an RB-Tree, set it to NULL / all zero.
*/
struct CRBTree {
CRBNode *root;
};
CRBNode *c_rbtree_first(CRBTree *t);
CRBNode *c_rbtree_last(CRBTree *t);
void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n);
void c_rbtree_remove(CRBTree *t, CRBNode *n);
/**
* c_rbnode_init() - mark a node as unlinked
* @n: node to operate on
*
* This marks the node @n as unlinked. The node will be set to a valid state
* that can never happen if the node is linked in a tree. Furthermore, this
* state is fully known to the implementation, and as such handled gracefully
* in all cases.
*
* You are *NOT* required to call this on your node. c_rbtree_add() can handle
* uninitialized nodes just fine. However, calling this allows to use
* c_rbnode_is_linked() to check for the state of a node. Furthermore,
* iterators and accessors can be called on initialized (yet unlinked) nodes.
*
* Use the C_RBNODE_INIT macro if you want to initialize static variables.
*/
static inline void c_rbnode_init(CRBNode *n) {
*n = (CRBNode)C_RBNODE_INIT(*n);
}
/**
* c_rbnode_is_linked() - check whether a node is linked
* @n: node to check, or NULL
*
* This checks whether the passed node is linked. If you pass NULL, or if the
* node is not linked into a tree, this will return false. Otherwise, this
* returns true.
*
* Note that you must have either linked the node or initialized it, before
* calling this function. Never call this function on uninitialized nodes.
* Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node
* as unlinked. You have to call c_rbnode_init() yourself after removal, or use
* the c_rbtree_remove_init() helper.
*
* Return: true if the node is linked, false if not.
*/
static inline _Bool c_rbnode_is_linked(CRBNode *n) {
return n && n->__parent_and_color != n;
}
/**
* c_rbnode_parent() - return parent pointer
* @n node to access
*
* This returns a pointer to the parent of the given node @n. If @n does not
* have a parent, NULL is returned. If @n is not linked, @n itself is returned.
*
* You should not call this on unlinked or uninitialized nodes! If you do, you
* better know how its semantics.
*
* Return: Pointer to parent.
*/
static inline CRBNode *c_rbnode_parent(CRBNode *n) {
return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL);
}
/**
* c_rbtree_remove_init() - safely remove node from tree and reinitialize it
* @t: tree to operate on
* @n: node to remove, or NULL
*
* This is almost the same as c_rbtree_remove(), but extends it slightly, to be
* more convenient to use in many cases:
* - if @n is unlinked or NULL, this is a no-op
* - @n is reinitialized after being removed
*/
static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) {
if (c_rbnode_is_linked(n)) {
c_rbtree_remove(t, n);
c_rbnode_init(n);
}
}
/**
* CRBCompareFunc - compare a node to a key
* @t: tree where the node is linked to
* @k: key to compare
* @n: node to compare
*
* If you use the tree-traversal helpers (which are optional), you need to
* provide this callback so they can compare nodes in a tree to the key you
* look for.
*
* The tree @t is provided as optional context to this callback. The key you
* look for is provided as @k, the current node that should be compared to is
* provided as @n. This function should work like strcmp(), that is, return -1
* if @key orders before @n, 0 if both compare equal, and 1 if it orders after
* @n.
*/
typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n);
/**
* c_rbtree_find_node() - find node
* @t: tree to search through
* @f: comparison function
* @k: key to search for
*
* This searches through @t for a node that compares equal to @k. The function
* @f must be provided by the caller, which is used to compare nodes to @k. See
* the documentation of CRBCompareFunc for details.
*
* If there are multiple entries that compare equal to @k, this will return a
* pseudo-randomly picked node. If you need stable lookup functions for trees
* where duplicate entries are allowed, you better code your own lookup.
*
* Return: Pointer to matching node, or NULL.
*/
static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) {
CRBNode *i;
assert(t);
assert(f);
i = t->root;
while (i) {
int v = f(t, (void *)k, i);
if (v < 0)
i = i->left;
else if (v > 0)
i = i->right;
else
return i;
}
return NULL;
}
/**
* c_rbtree_find_entry() - find entry
* @_t: tree to search through
* @_f: comparison function
* @_k: key to search for
* @_t: type of the structure that embeds the nodes
* @_o: name of the node-member in type @_t
*
* This is very similar to c_rbtree_find_node(), but instead of returning a
* pointer to the CRBNode, it returns a pointer to the surrounding object. This
* object must embed the CRBNode object. The type of the surrounding object
* must be given as @_t, and the name of the embedded CRBNode member as @_o.
*
* See c_rbtree_find_node() for more details.
*
* Return: Pointer to found entry, NULL if not found.
*/
#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \
((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \
(char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o)))
/**
* c_rbtree_find_slot() - find slot to insert new node
* @t: tree to search through
* @f: comparison function
* @k: key to search for
* @p: output storage for parent pointer
*
* This searches through @t just like c_rbtree_find_node() does. However,
* instead of returning a pointer to a node that compares equal to @k, this
* searches for a slot to insert a node with key @k. A pointer to the slot is
* returned, and a pointer to the parent of the slot is stored in @p. Both
* can be passed directly to c_rbtree_add(), together with your node to insert.
*
* If there already is a node in the tree, that compares equal to @k, this will
* return NULL and store the conflicting node in @p. In all other cases,
* this will return a pointer (non-NULL) to the empty slot to insert the node
* at. @p will point to the parent node of that slot.
*
* If you want trees that allow duplicate nodes, you better code your own
* insertion function.
*
* Return: Pointer to slot to insert node, or NULL on conflicts.
*/
static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) {
CRBNode **i;
assert(t);
assert(f);
assert(p);
i = &t->root;
*p = NULL;
while (*i) {
int v = f(t, (void *)k, *i);
*p = *i;
if (v < 0)
i = &(*i)->left;
else if (v > 0)
i = &(*i)->right;
else
return NULL;
}
return i;
}
#ifdef __cplusplus
}
#endif

View file

@ -41,8 +41,6 @@
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
#ifdef HAVE_SPLIT_USR
#define KBD_KEYMAP_DIRS \
"/usr/share/keymaps/\0" \

View file

@ -30,3 +30,12 @@ typedef enum RemoveFlags {
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
int rm_rf(const char *path, RemoveFlags flags);
/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
static inline void rm_rf_and_free(char *p) {
if (!p)
return;
(void) rm_rf(p, REMOVE_ROOT);
free(p);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_and_free);

View file

@ -255,7 +255,7 @@ int signal_from_string(const char *s) {
}
if (safe_atou(s, &u) >= 0) {
signo = (int) u + offset;
if (signo > 0 && signo < _NSIG)
if (SIGNAL_VALID(signo))
return signo;
}
return -EINVAL;

View file

@ -50,3 +50,7 @@ static inline void block_signals_reset(sigset_t *ss) {
assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \
t; \
})
static inline bool SIGNAL_VALID(int signo) {
return signo > 0 && signo < _NSIG;
}

View file

@ -558,6 +558,42 @@ int strv_extend(char ***l, const char *value) {
return strv_consume(l, v);
}
int strv_extend_front(char ***l, const char *value) {
size_t n, m;
char *v, **c;
assert(l);
/* Like strv_extend(), but prepends rather than appends the new entry */
if (!value)
return 0;
n = strv_length(*l);
/* Increase and overflow check. */
m = n + 2;
if (m < n)
return -ENOMEM;
v = strdup(value);
if (!v)
return -ENOMEM;
c = realloc_multiply(*l, sizeof(char*), m);
if (!c) {
free(v);
return -ENOMEM;
}
memmove(c+1, c, n * sizeof(char*));
c[0] = v;
c[n+1] = NULL;
*l = c;
return 0;
}
char **strv_uniq(char **l) {
char **i;

View file

@ -50,6 +50,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_extend_front(char ***l, const char *value);
int strv_push(char ***l, char *value);
int strv_push_pair(char ***l, char *a, char *b);
int strv_push_prepend(char ***l, char *value);

View file

@ -55,6 +55,7 @@
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
#include "umask-util.h"
#include "user-util.h"
#include "util.h"
@ -777,15 +778,24 @@ uint64_t physical_memory(void) {
return (uint64_t) mem * (uint64_t) page_size();
}
int update_reboot_param_file(const char *param) {
int r = 0;
int update_reboot_parameter_and_warn(const char *param) {
int r;
if (param) {
r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
} else
(void) unlink(REBOOT_PARAM_FILE);
if (isempty(param)) {
if (unlink("/run/systemd/reboot-param") < 0) {
if (errno == ENOENT)
return 0;
return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
}
return 0;
}
RUN_WITH_UMASK(0022)
r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_warning_errno(r, "Failed to write reboot parameter file: %m");
return 0;
}

View file

@ -184,6 +184,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
uint64_t physical_memory(void);
int update_reboot_param_file(const char *param);
int update_reboot_parameter_and_warn(const char *param);
int version(void);

View file

@ -149,7 +149,7 @@ static int automount_add_default_dependencies(Automount *a) {
if (!UNIT(a)->default_dependencies)
return 0;
if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);

View file

@ -149,7 +149,7 @@ static int busname_add_default_default_dependencies(BusName *n) {
if (r < 0)
return r;
if (UNIT(n)->manager->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(UNIT(n)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@ -318,7 +318,7 @@ static int busname_open_fd(BusName *n) {
if (n->starter_fd >= 0)
return 0;
mode = UNIT(n)->manager->running_as == MANAGER_SYSTEM ? "system" : "user";
mode = MANAGER_IS_SYSTEM(UNIT(n)->manager) ? "system" : "user";
n->starter_fd = bus_kernel_open_bus_fd(mode, &path);
if (n->starter_fd < 0)
return log_unit_warning_errno(UNIT(n), n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");

View file

@ -1265,7 +1265,7 @@ int manager_setup_cgroup(Manager *m) {
* it. This is to support live upgrades from older systemd
* versions where PID 1 was moved there. Also see
* cg_get_root_path(). */
if (!e && m->running_as == MANAGER_SYSTEM) {
if (!e && MANAGER_IS_SYSTEM(m)) {
e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
if (!e)
e = endswith(m->cgroup_root, "/system"); /* even more legacy */
@ -1318,7 +1318,7 @@ int manager_setup_cgroup(Manager *m) {
(void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
} else if (m->running_as == MANAGER_SYSTEM) {
} else if (MANAGER_IS_SYSTEM(m)) {
/* On the legacy hierarchy we only get
* notifications via cgroup agents. (Which

View file

@ -837,9 +837,9 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
if (isempty(uu)) {
if (isempty(uu))
c->user = mfree(c->user);
} else {
else {
char *t;
t = strdup(uu);
@ -864,9 +864,9 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
if (isempty(gg)) {
if (isempty(gg))
c->group = mfree(c->group);
} else {
else {
char *t;
t = strdup(gg);

View file

@ -58,7 +58,7 @@ int bus_kill_context_set_transient_property(
k = kill_mode_from_string(m);
if (k < 0)
return -EINVAL;
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Kill mode '%s' not known.", m);
if (mode != UNIT_CHECK) {
c->kill_mode = k;
@ -75,7 +75,7 @@ int bus_kill_context_set_transient_property(
if (r < 0)
return r;
if (sig <= 0 || sig >= _NSIG)
if (!SIGNAL_VALID(sig))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig);
if (mode != UNIT_CHECK) {

View file

@ -1187,7 +1187,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
if (r < 0)
return r;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
m->exit_code = MANAGER_REBOOT;
@ -1206,7 +1206,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
m->exit_code = MANAGER_POWEROFF;
@ -1225,7 +1225,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
if (r < 0)
return r;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
m->exit_code = MANAGER_HALT;
@ -1244,7 +1244,7 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
if (r < 0)
return r;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
m->exit_code = MANAGER_KEXEC;
@ -1265,7 +1265,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
if (r < 0)
return r;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
r = sd_bus_message_read(message, "ss", &root, &init);
@ -1433,7 +1433,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_
if (r < 0)
return r;
if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
m->return_value = code;
@ -1466,7 +1466,7 @@ static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bu
if (!h)
return -ENOMEM;
r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
r = unit_file_get_list(m->unit_file_scope, NULL, h);
if (r < 0)
goto fail;
@ -1498,7 +1498,6 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
Manager *m = userdata;
const char *name;
UnitFileState state;
UnitFileScope scope;
int r;
assert(message);
@ -1514,9 +1513,7 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_get_state(scope, NULL, name, &state);
r = unit_file_get_state(m->unit_file_scope, NULL, name, &state);
if (r < 0)
return r;
@ -1526,7 +1523,6 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
static int method_get_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *default_target = NULL;
Manager *m = userdata;
UnitFileScope scope;
int r;
assert(message);
@ -1538,9 +1534,7 @@ static int method_get_default_target(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_get_default(scope, NULL, &default_target);
r = unit_file_get_default(m->unit_file_scope, NULL, &default_target);
if (r < 0)
return r;
@ -1613,6 +1607,19 @@ fail:
return r;
}
static int install_error(sd_bus_error *error, int c) {
assert(c < 0);
if (c == -ESHUTDOWN)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked.");
if (c == -EADDRNOTAVAIL)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated.");
if (c == -ELOOP)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED, "Refusing to operate on linked unit file.");
return c;
}
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
@ -1624,7 +1631,6 @@ static int method_enable_unit_files_generic(
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
UnitFileScope scope;
int runtime, force, r;
assert(message);
@ -1644,13 +1650,11 @@ static int method_enable_unit_files_generic(
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
if (r == -ESHUTDOWN)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
if (r < 0)
return r;
r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
}
@ -1686,7 +1690,6 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
unsigned n_changes = 0;
Manager *m = userdata;
UnitFilePresetMode mm;
UnitFileScope scope;
int runtime, force, r;
const char *mode;
@ -1715,11 +1718,11 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
if (r < 0)
return r;
r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
}
@ -1734,7 +1737,6 @@ static int method_disable_unit_files_generic(
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
UnitFileScope scope;
int r, runtime;
assert(message);
@ -1748,17 +1750,17 @@ static int method_disable_unit_files_generic(
if (r < 0)
return r;
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = call(scope, runtime, NULL, l, &changes, &n_changes);
if (r < 0)
return r;
r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@ -1771,11 +1773,39 @@ static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_
return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error);
}
static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
Manager *m = userdata;
int r;
assert(message);
assert(m);
r = sd_bus_message_read_strv(message, &l);
if (r < 0)
return r;
r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
Manager *m = userdata;
UnitFileScope scope;
const char *name;
int force, r;
@ -1796,11 +1826,11 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
if (r < 0)
return r;
r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@ -1810,7 +1840,6 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
unsigned n_changes = 0;
Manager *m = userdata;
UnitFilePresetMode mm;
UnitFileScope scope;
const char *mode;
int force, runtime, r;
@ -1839,12 +1868,10 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return r;
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
@ -1855,7 +1882,6 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
Manager *m = userdata;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
UnitFileScope scope;
int runtime, force, r;
char *target;
char *type;
@ -1882,13 +1908,11 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
if (dep < 0)
return -EINVAL;
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
if (r == -ESHUTDOWN)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
if (r < 0)
return r;
r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
if (r < 0) {
unit_file_changes_free(changes, n_changes);
return install_error(error, r);
}
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@ -1924,7 +1948,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
@ -2025,6 +2049,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("PresetUnitFilesWithMode", "assbb", "ba(sss)", method_preset_unit_files_with_mode, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RevertUnitFiles", "as", "a(sss)", method_revert_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),

View file

@ -27,6 +27,7 @@
#include "locale-util.h"
#include "log.h"
#include "selinux-access.h"
#include "signal-util.h"
#include "special.h"
#include "string-util.h"
#include "strv.h"
@ -547,7 +548,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
}
if (signo <= 0 || signo >= _NSIG)
if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
r = bus_verify_manage_units_async_full(
@ -1002,7 +1003,6 @@ int bus_unit_queue_job(
type = JOB_TRY_RELOAD;
}
if (type == JOB_STOP &&
(u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
unit_active_state(u) == UNIT_INACTIVE)
@ -1259,6 +1259,7 @@ int bus_unit_set_properties(
}
int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
assert(u);
if (u->load_state == UNIT_LOADED)
return 0;

View file

@ -112,7 +112,7 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus
manager_notify_cgroup_empty(m, cgroup);
/* if running as system-instance, forward under our name */
if (m->running_as == MANAGER_SYSTEM && m->system_bus) {
if (MANAGER_IS_SYSTEM(m) && m->system_bus) {
r = sd_bus_message_rewind(message, 1);
if (r >= 0)
r = sd_bus_send(m->system_bus, message, NULL);
@ -690,7 +690,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
if (m->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(m)) {
/* When we run as system instance we get the Released
* signal via a direct connection */
@ -864,10 +864,10 @@ static int bus_init_api(Manager *m) {
return 0;
/* The API and system bus is the same if we are running in system mode */
if (m->running_as == MANAGER_SYSTEM && m->system_bus)
if (MANAGER_IS_SYSTEM(m) && m->system_bus)
bus = sd_bus_ref(m->system_bus);
else {
if (m->running_as == MANAGER_SYSTEM)
if (MANAGER_IS_SYSTEM(m))
r = sd_bus_open_system(&bus);
else
r = sd_bus_open_user(&bus);
@ -907,7 +907,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
assert(bus);
/* On kdbus or if we are a user instance we get the Released message via the system bus */
if (m->running_as == MANAGER_USER || m->kdbus_fd >= 0) {
if (MANAGER_IS_USER(m) || m->kdbus_fd >= 0) {
r = sd_bus_add_match(
bus,
NULL,
@ -932,7 +932,7 @@ static int bus_init_system(Manager *m) {
return 0;
/* The API and system bus is the same if we are running in system mode */
if (m->running_as == MANAGER_SYSTEM && m->api_bus) {
if (MANAGER_IS_SYSTEM(m) && m->api_bus) {
m->system_bus = sd_bus_ref(m->api_bus);
return 0;
}
@ -983,7 +983,7 @@ static int bus_init_private(Manager *m) {
if (m->kdbus_fd >= 0)
return 0;
if (m->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(m)) {
/* We want the private bus only when running as init */
if (getpid() != 1)
@ -1082,7 +1082,7 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
/* Possibly flush unwritten data, but only if we are
* unprivileged, since we don't want to sync here */
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
sd_bus_flush(*bus);
/* And destroy the object */

View file

@ -265,7 +265,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
assert(u);
assert(dev);
property = u->manager->running_as == MANAGER_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
wants = udev_device_get_property_value(dev, property);
if (!wants)
return 0;

View file

@ -47,7 +47,7 @@ int failure_action(
if (action == FAILURE_ACTION_NONE)
return -ECANCELED;
if (m->running_as == MANAGER_USER) {
if (!MANAGER_IS_SYSTEM(m)) {
/* Downgrade all options to simply exiting if we run
* in user mode */
@ -61,17 +61,17 @@ int failure_action(
case FAILURE_ACTION_REBOOT:
log_and_status(m, "Rebooting as result of failure.");
update_reboot_param_file(reboot_arg);
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET,
JOB_REPLACE_IRREVERSIBLY, NULL);
(void) update_reboot_parameter_and_warn(reboot_arg);
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
break;
case FAILURE_ACTION_REBOOT_FORCE:
log_and_status(m, "Forcibly rebooting as result of failure.");
update_reboot_param_file(reboot_arg);
(void) update_reboot_parameter_and_warn(reboot_arg);
m->exit_code = MANAGER_REBOOT;
break;
case FAILURE_ACTION_REBOOT_IMMEDIATE:
@ -79,9 +79,10 @@ int failure_action(
sync();
if (reboot_arg) {
if (!isempty(reboot_arg)) {
log_info("Rebooting with argument '%s'.", reboot_arg);
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg);
log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
}
log_info("Rebooting.");
@ -90,8 +91,7 @@ int failure_action(
case FAILURE_ACTION_POWEROFF:
log_and_status(m, "Powering off as result of failure.");
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET,
JOB_REPLACE_IRREVERSIBLY, NULL);
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
break;
case FAILURE_ACTION_POWEROFF_FORCE:

View file

@ -137,7 +137,7 @@ void job_uninstall(Job *j) {
/* Detach from next 'bigger' objects */
/* daemon-reload should be transparent to job observers */
if (j->manager->n_reloading <= 0)
if (!MANAGER_IS_RELOADING(j->manager))
bus_job_send_removed_signal(j);
*pj = NULL;
@ -1156,7 +1156,7 @@ void job_shutdown_magic(Job *j) {
if (j->type != JOB_START)
return;
if (j->unit->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(j->unit->manager))
return;
if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))

View file

@ -44,6 +44,7 @@ static int add_dependency_consumer(
}
int unit_load_dropin(Unit *u) {
_cleanup_strv_free_ char **l = NULL;
Iterator i;
char *t, **f;
int r;
@ -55,7 +56,7 @@ int unit_load_dropin(Unit *u) {
SET_FOREACH(t, u->names, i) {
char **p;
STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".wants", UNIT_WANTS,
add_dependency_consumer, u, NULL);
unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".requires", UNIT_REQUIRES,
@ -63,11 +64,19 @@ int unit_load_dropin(Unit *u) {
}
}
u->dropin_paths = strv_free(u->dropin_paths);
r = unit_find_dropin_paths(u, &u->dropin_paths);
r = unit_find_dropin_paths(u, &l);
if (r <= 0)
return 0;
if (!u->dropin_paths) {
u->dropin_paths = l;
l = NULL;
} else {
r = strv_extend_strv(&u->dropin_paths, l, true);
if (r < 0)
return log_oom();
}
STRV_FOREACH(f, u->dropin_paths) {
config_parse(u->id, *f, NULL,
UNIT_VTABLE(u)->sections,

View file

@ -25,7 +25,7 @@
/* Read service data supplementary drop-in directories */
static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
return unit_file_find_dropin_paths(u->manager->lookup_paths.unit_path,
return unit_file_find_dropin_paths(u->manager->lookup_paths.search_path,
u->manager->unit_path_cache,
u->names,
paths);

View file

@ -2495,7 +2495,7 @@ int config_parse_syscall_filter(
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
if (!c->no_new_privileges_set && MANAGER_IS_USER(u->manager))
c->no_new_privileges = true;
return 0;
@ -3583,7 +3583,7 @@ static int load_from_path(Unit *u, const char *path) {
} else {
char **p;
STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
/* Instead of opening the path right away, we manually
* follow all symlinks and add their name to our unit

View file

@ -259,9 +259,8 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
/* Hmm, we couldn't write it? So let's write it to
* /run/machine-id as a replacement */
RUN_WITH_UMASK(0022) {
RUN_WITH_UMASK(0022)
r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE);
}
if (r < 0) {
(void) unlink(run_machine_id);
return log_error_errno(r, "Cannot write %s: %m", run_machine_id);

View file

@ -81,6 +81,7 @@
#include "strv.h"
#include "switch-root.h"
#include "terminal-util.h"
#include "umask-util.h"
#include "user-util.h"
#include "virt.h"
#include "watchdog.h"
@ -94,7 +95,7 @@ static enum {
ACTION_DONE
} arg_action = ACTION_RUN;
static char *arg_default_unit = NULL;
static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
static bool arg_system = false;
static bool arg_dump_core = true;
static int arg_crash_chvt = -1;
static bool arg_crash_shell = false;
@ -688,11 +689,11 @@ static int parse_config_file(void) {
const char *fn, *conf_dirs_nulstr;
fn = arg_running_as == MANAGER_SYSTEM ?
fn = arg_system ?
PKGSYSCONFDIR "/system.conf" :
PKGSYSCONFDIR "/user.conf";
conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
conf_dirs_nulstr = arg_system ?
CONF_PATHS_NULSTR("systemd/system.conf.d") :
CONF_PATHS_NULSTR("systemd/user.conf.d");
@ -866,11 +867,11 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_SYSTEM:
arg_running_as = MANAGER_SYSTEM;
arg_system = true;
break;
case ARG_USER:
arg_running_as = MANAGER_USER;
arg_system = false;
break;
case ARG_TEST:
@ -1237,7 +1238,8 @@ static int write_container_id(void) {
if (isempty(c))
return 0;
r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
RUN_WITH_UMASK(0022)
r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
@ -1346,7 +1348,7 @@ int main(int argc, char *argv[]) {
if (getpid() == 1 && detect_container() <= 0) {
/* Running outside of a container as PID 1 */
arg_running_as = MANAGER_SYSTEM;
arg_system = true;
make_null_stdio();
log_set_target(LOG_TARGET_KMSG);
log_open();
@ -1430,7 +1432,7 @@ int main(int argc, char *argv[]) {
} else if (getpid() == 1) {
/* Running inside a container, as PID 1 */
arg_running_as = MANAGER_SYSTEM;
arg_system = true;
log_set_target(LOG_TARGET_CONSOLE);
log_close_console(); /* force reopen of /dev/console */
log_open();
@ -1443,7 +1445,7 @@ int main(int argc, char *argv[]) {
kernel_timestamp = DUAL_TIMESTAMP_NULL;
} else {
/* Running as user instance */
arg_running_as = MANAGER_USER;
arg_system = false;
log_set_target(LOG_TARGET_AUTO);
log_open();
@ -1501,7 +1503,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
if (arg_running_as == MANAGER_SYSTEM) {
if (arg_system) {
r = parse_proc_cmdline(parse_proc_cmdline_item);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
@ -1522,14 +1524,14 @@ int main(int argc, char *argv[]) {
goto finish;
}
if (arg_running_as == MANAGER_USER &&
if (!arg_system &&
arg_action == ACTION_RUN &&
sd_booted() <= 0) {
log_error("Trying to run as user instance, but the system has not been booted with systemd.");
goto finish;
}
if (arg_running_as == MANAGER_SYSTEM &&
if (arg_system &&
arg_action == ACTION_RUN &&
running_in_chroot() > 0) {
log_error("Cannot be run in a chroot() environment.");
@ -1557,7 +1559,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
if (arg_running_as == MANAGER_USER &&
if (!arg_system &&
!getenv("XDG_RUNTIME_DIR")) {
log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
goto finish;
@ -1580,7 +1582,7 @@ int main(int argc, char *argv[]) {
if (arg_serialization)
assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
if (arg_running_as == MANAGER_SYSTEM)
if (arg_system)
/* Become a session leader if we aren't one yet. */
setsid();
@ -1589,7 +1591,7 @@ int main(int argc, char *argv[]) {
/* Reset the console, but only if this is really init and we
* are freshly booted */
if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) {
if (arg_system && arg_action == ACTION_RUN) {
/* If we are init, we connect stdin/stdout/stderr to
* /dev/null and make sure we don't have a controlling
@ -1616,7 +1618,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
if (arg_running_as == MANAGER_SYSTEM) {
if (arg_system) {
int v;
log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
@ -1652,7 +1654,7 @@ int main(int argc, char *argv[]) {
arg_action == ACTION_TEST ? " test" : "", getuid(), t);
}
if (arg_running_as == MANAGER_SYSTEM && !skip_setup) {
if (arg_system && !skip_setup) {
if (arg_show_status > 0)
status_welcome();
@ -1664,7 +1666,7 @@ int main(int argc, char *argv[]) {
test_usr();
}
if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
watchdog_set_timeout(&arg_runtime_watchdog);
if (arg_timer_slack_nsec != NSEC_INFINITY)
@ -1694,12 +1696,12 @@ int main(int argc, char *argv[]) {
}
}
if (arg_running_as == MANAGER_USER)
if (!arg_system)
/* Become reaper of our children */
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
log_warning_errno(errno, "Failed to make us a subreaper: %m");
if (arg_running_as == MANAGER_SYSTEM) {
if (arg_system) {
bump_rlimit_nofile(&saved_rlimit_nofile);
if (empty_etc) {
@ -1711,7 +1713,7 @@ int main(int argc, char *argv[]) {
}
}
r = manager_new(arg_running_as, arg_action == ACTION_TEST, &m);
r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, arg_action == ACTION_TEST, &m);
if (r < 0) {
log_emergency_errno(r, "Failed to allocate manager object: %m");
error_message = "Failed to allocate manager object";
@ -1874,7 +1876,7 @@ int main(int argc, char *argv[]) {
case MANAGER_EXIT:
retval = m->return_value;
if (m->running_as == MANAGER_USER) {
if (MANAGER_IS_USER(m)) {
log_debug("Exit.");
goto finish;
}
@ -1970,7 +1972,7 @@ finish:
args[i++] = SYSTEMD_BINARY_PATH;
if (switch_root_dir)
args[i++] = "--switched-root";
args[i++] = arg_running_as == MANAGER_SYSTEM ? "--system" : "--user";
args[i++] = arg_system ? "--system" : "--user";
args[i++] = "--deserialize";
args[i++] = sfd;
args[i++] = NULL;

View file

@ -49,6 +49,7 @@
#include "dbus-manager.h"
#include "dbus-unit.h"
#include "dbus.h"
#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
#include "exit-status.h"
@ -63,6 +64,7 @@
#include "manager.h"
#include "missing.h"
#include "mkdir.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
@ -98,7 +100,6 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
static int manager_run_generators(Manager *m);
static void manager_undo_generators(Manager *m);
static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
@ -491,7 +492,7 @@ static int manager_setup_signals(Manager *m) {
if (r < 0)
return r;
if (m->running_as == MANAGER_SYSTEM)
if (MANAGER_IS_SYSTEM(m))
return enable_special_signals(m);
return 0;
@ -518,7 +519,7 @@ static void manager_clean_environment(Manager *m) {
static int manager_default_environment(Manager *m) {
assert(m);
if (m->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(m)) {
/* The system manager always starts with a clean
* environment for its children. It does not import
* the kernel or the parents exported variables.
@ -547,43 +548,36 @@ static int manager_default_environment(Manager *m) {
}
int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
static const char * const unit_log_fields[_MANAGER_RUNNING_AS_MAX] = {
[MANAGER_SYSTEM] = "UNIT=",
[MANAGER_USER] = "USER_UNIT=",
};
static const char * const unit_log_format_strings[_MANAGER_RUNNING_AS_MAX] = {
[MANAGER_SYSTEM] = "UNIT=%s",
[MANAGER_USER] = "USER_UNIT=%s",
};
int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
Manager *m;
int r;
assert(_m);
assert(running_as >= 0);
assert(running_as < _MANAGER_RUNNING_AS_MAX);
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER));
m = new0(Manager, 1);
if (!m)
return -ENOMEM;
#ifdef ENABLE_EFI
if (running_as == MANAGER_SYSTEM && detect_container() <= 0)
boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
#endif
m->running_as = running_as;
m->unit_file_scope = scope;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
m->default_tasks_accounting = true;
m->default_tasks_max = UINT64_C(512);
#ifdef ENABLE_EFI
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
#endif
/* Prepare log fields we can use for structured logging */
m->unit_log_field = unit_log_fields[running_as];
m->unit_log_format_string = unit_log_format_strings[running_as];
if (MANAGER_IS_SYSTEM(m)) {
m->unit_log_field = "UNIT=";
m->unit_log_format_string = "UNIT=%s";
} else {
m->unit_log_field = "USER_UNIT=";
m->unit_log_format_string = "USER_UNIT=%s";
}
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
@ -683,6 +677,7 @@ static int manager_setup_notify(Manager *m) {
.sa.sa_family = AF_UNIX,
};
static const int one = 1;
const char *e;
/* First free all secondary fields */
m->notify_socket = mfree(m->notify_socket);
@ -694,19 +689,13 @@ static int manager_setup_notify(Manager *m) {
fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
if (m->running_as == MANAGER_SYSTEM)
m->notify_socket = strdup("/run/systemd/notify");
else {
const char *e;
e = getenv("XDG_RUNTIME_DIR");
if (!e) {
log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m");
return -EINVAL;
}
m->notify_socket = strappend(e, "/systemd/notify");
e = manager_get_runtime_prefix(m);
if (!e) {
log_error("Failed to determine runtime prefix.");
return -EINVAL;
}
m->notify_socket = strappend(e, "/systemd/notify");
if (!m->notify_socket)
return log_oom();
@ -756,8 +745,8 @@ static int manager_setup_kdbus(Manager *m) {
return -ESOCKTNOSUPPORT;
m->kdbus_fd = bus_kernel_create_bus(
m->running_as == MANAGER_SYSTEM ? "system" : "user",
m->running_as == MANAGER_SYSTEM, &p);
MANAGER_IS_SYSTEM(m) ? "system" : "user",
MANAGER_IS_SYSTEM(m), &p);
if (m->kdbus_fd < 0)
return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
@ -778,7 +767,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) {
try_bus_connect =
m->kdbus_fd >= 0 ||
reexecuting ||
(m->running_as == MANAGER_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
(MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"));
/* Try to connect to the buses, if possible. */
return bus_init(m, try_bus_connect);
@ -940,7 +929,7 @@ Manager* manager_free(Manager *m) {
* around */
manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
manager_undo_generators(m);
lookup_paths_flush_generator(&m->lookup_paths);
bus_done(m);
@ -1037,7 +1026,6 @@ static void manager_coldplug(Manager *m) {
static void manager_build_unit_path_cache(Manager *m) {
char **i;
_cleanup_closedir_ DIR *d = NULL;
int r;
assert(m);
@ -1046,29 +1034,27 @@ static void manager_build_unit_path_cache(Manager *m) {
m->unit_path_cache = set_new(&string_hash_ops);
if (!m->unit_path_cache) {
log_error("Failed to allocate unit path cache.");
return;
r = -ENOMEM;
goto fail;
}
/* This simply builds a list of files we know exist, so that
* we don't always have to go to disk */
STRV_FOREACH(i, m->lookup_paths.unit_path) {
STRV_FOREACH(i, m->lookup_paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
d = opendir(*i);
if (!d) {
if (errno != ENOENT)
log_error_errno(errno, "Failed to open directory %s: %m", *i);
log_warning_errno(errno, "Failed to open directory %s, ignoring: %m", *i);
continue;
}
while ((de = readdir(d))) {
FOREACH_DIRENT(de, d, r = -errno; goto fail) {
char *p;
if (hidden_file(de->d_name))
continue;
p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
if (!p) {
r = -ENOMEM;
@ -1079,20 +1065,15 @@ static void manager_build_unit_path_cache(Manager *m) {
if (r < 0)
goto fail;
}
d = safe_closedir(d);
}
return;
fail:
log_error_errno(r, "Failed to build unit path cache: %m");
set_free_free(m->unit_path_cache);
m->unit_path_cache = NULL;
log_warning_errno(r, "Failed to build unit path cache, proceeding without: %m");
m->unit_path_cache = set_free_free(m->unit_path_cache);
}
static void manager_distribute_fds(Manager *m, FDSet *fds) {
Iterator i;
Unit *u;
@ -1116,21 +1097,22 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
assert(m);
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
if (r < 0)
return r;
/* Make sure the transient directory always exists, so that it remains in the search path */
r = mkdir_p_label(m->lookup_paths.transient, 0755);
if (r < 0)
return r;
dual_timestamp_get(&m->generators_start_timestamp);
r = manager_run_generators(m);
dual_timestamp_get(&m->generators_finish_timestamp);
if (r < 0)
return r;
r = lookup_paths_init(
&m->lookup_paths, m->running_as, true,
NULL,
m->generator_unit_path,
m->generator_unit_path_early,
m->generator_unit_path_late);
if (r < 0)
return r;
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
/* If we will deserialize make sure that during enumeration
@ -1744,7 +1726,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
}
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
(sfsi.ssi_signo == SIGTERM && m->running_as == MANAGER_USER)
(sfsi.ssi_signo == SIGTERM && MANAGER_IS_USER(m))
? LOG_DEBUG : LOG_INFO,
&sfsi);
@ -1755,7 +1737,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGTERM:
if (m->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(m)) {
/* This is for compatibility with the
* original sysvinit */
m->exit_code = MANAGER_REEXECUTE;
@ -1765,7 +1747,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
/* Fall through */
case SIGINT:
if (m->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(m)) {
/* If the user presses C-A-D more than
* 7 times within 2s, we reboot
@ -1791,14 +1773,14 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGWINCH:
if (m->running_as == MANAGER_SYSTEM)
if (MANAGER_IS_SYSTEM(m))
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
break;
case SIGPWR:
if (m->running_as == MANAGER_SYSTEM)
if (MANAGER_IS_SYSTEM(m))
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
@ -1906,7 +1888,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case 24:
if (m->running_as == MANAGER_USER) {
if (MANAGER_IS_USER(m)) {
m->exit_code = MANAGER_EXIT;
return 0;
}
@ -2022,7 +2004,7 @@ int manager_loop(Manager *m) {
while (m->exit_code == MANAGER_OK) {
usec_t wait_usec;
if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM)
if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m))
watchdog_ping();
if (!ratelimit_test(&rl)) {
@ -2047,7 +2029,7 @@ int manager_loop(Manager *m) {
continue;
/* Sleep for half the watchdog time */
if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) {
if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m)) {
wait_usec = m->runtime_watchdog / 2;
if (wait_usec <= 0)
wait_usec = 1;
@ -2118,7 +2100,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
const char *msg;
int audit_fd, r;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return;
audit_fd = get_audit_fd();
@ -2127,7 +2109,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
/* Don't generate audit events if the service was already
* started and we're just deserializing */
if (m->n_reloading > 0)
if (MANAGER_IS_RELOADING(m))
return;
if (u->type != UNIT_SERVICE)
@ -2161,10 +2143,10 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
if (m->n_reloading > 0)
if (MANAGER_IS_RELOADING(m))
return;
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return;
if (detect_container() > 0)
@ -2208,7 +2190,7 @@ int manager_open_serialization(Manager *m, FILE **_f) {
assert(_f);
path = m->running_as == MANAGER_SYSTEM ? "/run/systemd" : "/tmp";
path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp";
fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
@ -2539,23 +2521,19 @@ int manager_reload(Manager *m) {
/* From here on there is no way back. */
manager_clear_jobs_and_units(m);
manager_undo_generators(m);
lookup_paths_flush_generator(&m->lookup_paths);
lookup_paths_free(&m->lookup_paths);
q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
if (q < 0 && r >= 0)
r = q;
/* Find new unit paths */
q = manager_run_generators(m);
if (q < 0 && r >= 0)
r = q;
q = lookup_paths_init(
&m->lookup_paths, m->running_as, true,
NULL,
m->generator_unit_path,
m->generator_unit_path_early,
m->generator_unit_path_late);
if (q < 0 && r >= 0)
r = q;
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
/* First, enumerate what we can from all config files */
@ -2589,12 +2567,6 @@ int manager_reload(Manager *m) {
return r;
}
bool manager_is_reloading_or_reexecuting(Manager *m) {
assert(m);
return m->n_reloading != 0;
}
void manager_reset_failed(Manager *m) {
Unit *u;
Iterator i;
@ -2626,7 +2598,7 @@ static void manager_notify_finished(Manager *m) {
if (m->test_run)
return;
if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0) {
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
* and m->firmware_usec.monotonic and
@ -2691,7 +2663,7 @@ static void manager_notify_finished(Manager *m) {
void manager_check_finished(Manager *m) {
assert(m);
if (m->n_reloading > 0)
if (MANAGER_IS_RELOADING(m))
return;
/* Verify that we are actually running currently. Initially
@ -2732,77 +2704,6 @@ void manager_check_finished(Manager *m) {
manager_invalidate_startup_units(m);
}
static int create_generator_dir(Manager *m, char **generator, const char *name) {
char *p;
int r;
assert(m);
assert(generator);
assert(name);
if (*generator)
return 0;
if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
/* systemd --system, not running --test */
p = strappend("/run/systemd/", name);
if (!p)
return log_oom();
r = mkdir_p_label(p, 0755);
if (r < 0) {
log_error_errno(r, "Failed to create generator directory %s: %m", p);
free(p);
return r;
}
} else if (m->running_as == MANAGER_USER) {
const char *s = NULL;
s = getenv("XDG_RUNTIME_DIR");
if (!s)
return -EINVAL;
p = strjoin(s, "/systemd/", name, NULL);
if (!p)
return log_oom();
r = mkdir_p_label(p, 0755);
if (r < 0) {
log_error_errno(r, "Failed to create generator directory %s: %m", p);
free(p);
return r;
}
} else {
/* systemd --system --test */
p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
if (!p)
return log_oom();
if (!mkdtemp(p)) {
log_error_errno(errno, "Failed to create generator directory %s: %m", p);
free(p);
return -errno;
}
}
*generator = p;
return 0;
}
static void trim_generator_dir(Manager *m, char **generator) {
assert(m);
assert(generator);
if (!*generator)
return;
if (rmdir(*generator) >= 0)
*generator = mfree(*generator);
return;
}
static int manager_run_generators(Manager *m) {
_cleanup_strv_free_ char **paths = NULL;
const char *argv[5];
@ -2814,71 +2715,40 @@ static int manager_run_generators(Manager *m) {
if (m->test_run)
return 0;
paths = generator_paths(m->running_as);
paths = generator_binary_paths(m->unit_file_scope);
if (!paths)
return log_oom();
/* Optimize by skipping the whole process by not creating output directories
* if no generators are found. */
STRV_FOREACH(path, paths) {
r = access(*path, F_OK);
if (r == 0)
if (access(*path, F_OK) >= 0)
goto found;
if (errno != ENOENT)
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
}
return 0;
found:
r = create_generator_dir(m, &m->generator_unit_path, "generator");
if (r < 0)
goto finish;
r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
if (r < 0)
goto finish;
r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
r = lookup_paths_mkdir_generator(&m->lookup_paths);
if (r < 0)
goto finish;
argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
argv[1] = m->generator_unit_path;
argv[2] = m->generator_unit_path_early;
argv[3] = m->generator_unit_path_late;
argv[1] = m->lookup_paths.generator;
argv[2] = m->lookup_paths.generator_early;
argv[3] = m->lookup_paths.generator_late;
argv[4] = NULL;
RUN_WITH_UMASK(0022)
execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
finish:
trim_generator_dir(m, &m->generator_unit_path);
trim_generator_dir(m, &m->generator_unit_path_early);
trim_generator_dir(m, &m->generator_unit_path_late);
lookup_paths_trim_generator(&m->lookup_paths);
return r;
}
static void remove_generator_dir(Manager *m, char **generator) {
assert(m);
assert(generator);
if (!*generator)
return;
strv_remove(m->lookup_paths.unit_path, *generator);
(void) rm_rf(*generator, REMOVE_ROOT);
*generator = mfree(*generator);
}
static void manager_undo_generators(Manager *m) {
assert(m);
remove_generator_dir(m, &m->generator_unit_path);
remove_generator_dir(m, &m->generator_unit_path_early);
remove_generator_dir(m, &m->generator_unit_path_late);
}
int manager_environment_add(Manager *m, char **minus, char **plus) {
char **a = NULL, **b = NULL, **l;
assert(m);
@ -2941,7 +2811,7 @@ void manager_recheck_journal(Manager *m) {
assert(m);
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return;
u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
@ -2965,7 +2835,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
assert(m);
assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return;
if (m->show_status != mode)
@ -2982,7 +2852,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
static bool manager_get_show_status(Manager *m, StatusType type) {
assert(m);
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return false;
if (m->no_console_output)
@ -3004,7 +2874,7 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
void manager_set_first_boot(Manager *m, bool b) {
assert(m);
if (m->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(m))
return;
if (m->first_boot != (int) b) {
@ -3050,7 +2920,7 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
const char *manager_get_runtime_prefix(Manager *m) {
assert(m);
return m->running_as == MANAGER_SYSTEM ?
return MANAGER_IS_SYSTEM(m) ?
"/run" :
getenv("XDG_RUNTIME_DIR");
}

View file

@ -140,6 +140,7 @@ struct Manager {
sd_event_source *jobs_in_progress_event_source;
UnitFileScope unit_file_scope;
LookupPaths lookup_paths;
Set *unit_path_cache;
@ -162,10 +163,6 @@ struct Manager {
dual_timestamp units_load_start_timestamp;
dual_timestamp units_load_finish_timestamp;
char *generator_unit_path;
char *generator_unit_path_early;
char *generator_unit_path_late;
struct udev* udev;
/* Data specific to the device subsystem */
@ -228,7 +225,6 @@ struct Manager {
unsigned n_in_gc_queue;
/* Flags */
ManagerRunningAs running_as;
ManagerExitCode exit_code:5;
bool dispatching_load_queue:1;
@ -304,10 +300,15 @@ struct Manager {
const char *unit_log_field;
const char *unit_log_format_string;
int first_boot;
int first_boot; /* tri-state */
};
int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM)
#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0)
int manager_new(UnitFileScope scope, bool test_run, Manager **m);
Manager* manager_free(Manager *m);
void manager_enumerate(Manager *m);
@ -345,8 +346,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
int manager_reload(Manager *m);
bool manager_is_reloading_or_reexecuting(Manager *m) _pure_;
void manager_reset_failed(Manager *m);
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);

View file

@ -336,8 +336,7 @@ static int mount_add_device_links(Mount *m) {
if (path_equal(m->where, "/"))
return 0;
if (mount_is_auto(p) && !mount_is_automount(p) &&
UNIT(m)->manager->running_as == MANAGER_SYSTEM)
if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager))
device_wants_mount = true;
r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
@ -353,7 +352,7 @@ static int mount_add_quota_links(Mount *m) {
assert(m);
if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return 0;
p = get_mount_parameters_fragment(m);
@ -400,7 +399,7 @@ static int mount_add_default_dependencies(Mount *m) {
if (!UNIT(m)->default_dependencies)
return 0;
if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return 0;
/* We do not add any default dependencies to /, /usr or
@ -1396,7 +1395,7 @@ static int mount_setup_unit(
goto fail;
}
if (m->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(m)) {
const char* target;
target = mount_needs_network(options, fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
@ -1424,7 +1423,7 @@ static int mount_setup_unit(
}
}
if (m->running_as == MANAGER_SYSTEM &&
if (MANAGER_IS_SYSTEM(m) &&
mount_needs_network(options, fstype)) {
/* _netdev option may have shown up late, or on a
* remount. Add remote-fs dependencies, even though

View file

@ -174,6 +174,10 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="LinkUnitFiles"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="RevertUnitFiles"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="PresetUnitFiles"/>

View file

@ -318,7 +318,7 @@ static int path_add_default_dependencies(Path *p) {
if (r < 0)
return r;
if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;

View file

@ -138,7 +138,7 @@ static int scope_verify(Scope *s) {
return 0;
if (set_isempty(UNIT(s)->pids) &&
!manager_is_reloading_or_reexecuting(UNIT(s)->manager) &&
!MANAGER_IS_RELOADING(UNIT(s)->manager) &&
!unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
return -EINVAL;
@ -154,26 +154,27 @@ static int scope_load(Unit *u) {
assert(s);
assert(u->load_state == UNIT_STUB);
if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
/* Refuse to load non-transient scope units, but allow them while reloading. */
return -ENOENT;
u->load_state = UNIT_LOADED;
r = unit_load_dropin(u);
r = unit_load_fragment_and_dropin_optional(u);
if (r < 0)
return r;
r = unit_patch_contexts(u);
if (r < 0)
return r;
if (u->load_state == UNIT_LOADED) {
r = unit_patch_contexts(u);
if (r < 0)
return r;
r = unit_set_default_slice(u);
if (r < 0)
return r;
r = unit_set_default_slice(u);
if (r < 0)
return r;
r = scope_add_default_dependencies(s);
if (r < 0)
return r;
r = scope_add_default_dependencies(s);
if (r < 0)
return r;
}
return scope_verify(s);
}
@ -292,7 +293,7 @@ static int scope_start(Unit *u) {
assert(s->state == SCOPE_DEAD);
if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
return -ENOENT;
(void) unit_realize_cgroup(u);

View file

@ -523,7 +523,7 @@ static int service_add_default_dependencies(Service *s) {
/* Add a number of automatic dependencies useful for the
* majority of services. */
if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
/* First, pull in the really early boot stuff, and
* require it, so that we fail if we can't acquire
* it. */
@ -920,7 +920,7 @@ static void service_set_state(Service *s, ServiceState state) {
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves... */
if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
if (state == SERVICE_EXITED && !MANAGER_IS_RELOADING(UNIT(s)->manager))
unit_prune_cgroup(UNIT(s));
/* For remain_after_exit services, let's see if we can "release" the
@ -1211,7 +1211,7 @@ static int service_spawn(
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
return -ENOMEM;
if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
return -ENOMEM;

View file

@ -397,9 +397,14 @@ int main(int argc, char *argv[]) {
if (!in_container) {
_cleanup_free_ char *param = NULL;
if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
r = read_one_line_file("/run/systemd/reboot-param", &param);
if (r < 0)
log_warning_errno(r, "Failed to read reboot parameter file: %m");
if (!isempty(param)) {
log_info("Rebooting with argument '%s'.", param);
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
}
}

View file

@ -135,6 +135,7 @@ static int slice_load(Unit *u) {
int r;
assert(s);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin_optional(u);
if (r < 0)

View file

@ -301,7 +301,7 @@ static int socket_add_default_dependencies(Socket *s) {
if (r < 0)
return r;
if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;

View file

@ -198,7 +198,7 @@ static int swap_add_device_links(Swap *s) {
return 0;
if (is_device_path(s->what))
return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM, UNIT_BINDS_TO);
return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO);
else
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
@ -214,7 +214,7 @@ static int swap_add_default_dependencies(Swap *s) {
if (!UNIT(s)->default_dependencies)
return 0;
if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
return 0;
if (detect_container() > 0)

View file

@ -109,7 +109,7 @@ static int timer_add_default_dependencies(Timer *t) {
if (r < 0)
return r;
if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@ -135,7 +135,7 @@ static int timer_setup_persistent(Timer *t) {
if (!t->persistent)
return 0;
if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
if (r < 0)

View file

@ -855,7 +855,7 @@ int transaction_add_job_and_dependencies(
* This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
* This way, we "recursively" coldplug units, ensuring that we do not look at state of
* not-yet-coldplugged units. */
if (unit->manager->n_reloading > 0)
if (MANAGER_IS_RELOADING(unit->manager))
unit_coldplug(unit);
/* log_debug("Pulling in %s/%s from %s/%s", */

View file

@ -140,14 +140,9 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char **
assert(u);
if (u->manager->running_as == MANAGER_SYSTEM)
e = "/run";
else {
e = getenv("XDG_RUNTIME_DIR");
if (!e)
return -EOPNOTSUPP;
}
e = manager_get_runtime_prefix(u->manager);
if (!e)
return -EOPNOTSUPP;
n = strdup(e);
if (!n)
return -ENOMEM;

View file

@ -47,11 +47,13 @@
#include "path-util.h"
#include "process-util.h"
#include "set.h"
#include "signal-util.h"
#include "special.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "umask-util.h"
#include "unit-name.h"
#include "unit.h"
#include "user-util.h"
@ -418,13 +420,22 @@ static void unit_remove_transient(Unit *u) {
(void) unlink(u->fragment_path);
STRV_FOREACH(i, u->dropin_paths) {
_cleanup_free_ char *p = NULL;
_cleanup_free_ char *p = NULL, *pp = NULL;
p = dirname_malloc(*i); /* Get the drop-in directory from the drop-in file */
if (!p)
continue;
pp = dirname_malloc(p); /* Get the config directory from the drop-in directory */
if (!pp)
continue;
/* Only drop transient drop-ins */
if (!path_equal(u->manager->lookup_paths.transient, pp))
continue;
(void) unlink(*i);
p = dirname_malloc(*i);
if (p)
(void) rmdir(p);
(void) rmdir(p);
}
}
@ -483,7 +494,10 @@ void unit_free(Unit *u) {
assert(u);
if (u->manager->n_reloading <= 0)
if (u->transient_file)
fclose(u->transient_file);
if (!MANAGER_IS_RELOADING(u->manager))
unit_remove_transient(u);
bus_unit_send_removed_signal(u);
@ -814,7 +828,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
return r;
}
if (u->manager->running_as != MANAGER_SYSTEM)
if (!MANAGER_IS_SYSTEM(u->manager))
return 0;
if (c->private_tmp) {
@ -1222,6 +1236,17 @@ int unit_load(Unit *u) {
if (u->load_state != UNIT_STUB)
return 0;
if (u->transient_file) {
r = fflush_and_check(u->transient_file);
if (r < 0)
goto fail;
fclose(u->transient_file);
u->transient_file = NULL;
u->dropin_mtime = now(CLOCK_REALTIME);
}
if (UNIT_VTABLE(u)->load) {
r = UNIT_VTABLE(u)->load(u);
if (r < 0)
@ -1834,7 +1859,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
m = u->manager;
/* Update timestamps for state changes */
if (m->n_reloading <= 0) {
if (!MANAGER_IS_RELOADING(m)) {
dual_timestamp_get(&u->state_change_timestamp);
if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
@ -1941,7 +1966,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
} else
unexpected = true;
if (m->n_reloading <= 0) {
if (!MANAGER_IS_RELOADING(m)) {
/* If this state change happened without being
* requested by a job, then let's retroactively start
@ -1978,7 +2003,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->type == UNIT_SERVICE &&
!UNIT_IS_ACTIVE_OR_RELOADING(os) &&
m->n_reloading <= 0) {
!MANAGER_IS_RELOADING(m)) {
/* Write audit record if we have just finished starting up */
manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
u->in_audit = true;
@ -1995,7 +2020,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->type == UNIT_SERVICE &&
UNIT_IS_INACTIVE_OR_FAILED(ns) &&
!UNIT_IS_INACTIVE_OR_FAILED(os) &&
m->n_reloading <= 0) {
!MANAGER_IS_RELOADING(m)) {
/* Hmm, if there was no start record written
* write it now, so that we always have a nice
@ -2016,7 +2041,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
manager_recheck_journal(m);
unit_trigger_notify(u);
if (u->manager->n_reloading <= 0) {
if (!MANAGER_IS_RELOADING(u->manager)) {
/* Maybe we finished startup and are now ready for
* being stopped because unneeded? */
unit_check_unneeded(u);
@ -2413,7 +2438,7 @@ int unit_set_default_slice(Unit *u) {
if (!escaped)
return -ENOMEM;
if (u->manager->running_as == MANAGER_SYSTEM)
if (MANAGER_IS_SYSTEM(u->manager))
b = strjoin("system-", escaped, ".slice", NULL);
else
b = strappend(escaped, ".slice");
@ -2423,7 +2448,7 @@ int unit_set_default_slice(Unit *u) {
slice_name = b;
} else
slice_name =
u->manager->running_as == MANAGER_SYSTEM && !unit_has_name(u, SPECIAL_INIT_SCOPE)
MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE)
? SPECIAL_SYSTEM_SLICE
: SPECIAL_ROOT_SLICE;
@ -2884,7 +2909,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
return r;
r = unit_add_two_dependencies(u, UNIT_AFTER,
u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS,
MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS,
device, true);
if (r < 0)
return r;
@ -3040,8 +3065,7 @@ bool unit_active_or_pending(Unit *u) {
int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
assert(u);
assert(w >= 0 && w < _KILL_WHO_MAX);
assert(signo > 0);
assert(signo < _NSIG);
assert(SIGNAL_VALID(signo));
if (!UNIT_VTABLE(u)->kill)
return -EOPNOTSUPP;
@ -3158,7 +3182,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
if (u->unit_file_state < 0 && u->fragment_path) {
r = unit_file_get_state(
u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
u->manager->unit_file_scope,
NULL,
basename(u->fragment_path),
&u->unit_file_state);
@ -3174,7 +3198,7 @@ int unit_get_unit_file_preset(Unit *u) {
if (u->unit_file_preset < 0 && u->fragment_path)
u->unit_file_preset = unit_file_query_preset(
u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
u->manager->unit_file_scope,
NULL,
basename(u->fragment_path));
@ -3225,7 +3249,7 @@ int unit_patch_contexts(Unit *u) {
return -ENOMEM;
}
if (u->manager->running_as == MANAGER_USER &&
if (MANAGER_IS_USER(u->manager) &&
!ec->working_directory) {
r = get_home_dir(&ec->working_directory);
@ -3237,7 +3261,7 @@ int unit_patch_contexts(Unit *u) {
ec->working_directory_missing_ok = true;
}
if (u->manager->running_as == MANAGER_USER &&
if (MANAGER_IS_USER(u->manager) &&
(ec->syscall_whitelist ||
!set_isempty(ec->syscall_filter) ||
!set_isempty(ec->syscall_archs) ||
@ -3315,59 +3339,62 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
return *(ExecRuntime**) ((uint8_t*) u + offset);
}
static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) {
static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
assert(u);
if (u->manager->running_as == MANAGER_USER) {
int r;
if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT))
return NULL;
if (mode == UNIT_PERSISTENT && !transient)
r = user_config_home(dir);
else
r = user_runtime_dir(dir);
if (r == 0)
return -ENOENT;
if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */
return u->manager->lookup_paths.transient;
return r;
}
if (mode == UNIT_RUNTIME)
return u->manager->lookup_paths.runtime_control;
if (mode == UNIT_PERSISTENT && !transient)
*dir = strdup("/etc/systemd/system");
else
*dir = strdup("/run/systemd/system");
if (!*dir)
return -ENOMEM;
if (mode == UNIT_PERSISTENT)
return u->manager->lookup_paths.persistent_control;
return 0;
return NULL;
}
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
_cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
_cleanup_free_ char *p = NULL, *q = NULL;
const char *dir, *prefixed;
int r;
assert(u);
if (u->transient_file) {
/* When this is a transient unit file in creation, then let's not create a new drop-in but instead
* write to the transient unit file. */
fputs(data, u->transient_file);
return 0;
}
if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
return 0;
r = unit_drop_in_dir(u, mode, u->transient, &dir);
if (r < 0)
return r;
dir = unit_drop_in_dir(u, mode);
if (!dir)
return -EINVAL;
r = write_drop_in(dir, u->id, 50, name, data);
if (r < 0)
return r;
prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n",
data);
r = drop_in_file(dir, u->id, 50, name, &p, &q);
if (r < 0)
return r;
r = strv_extend(&u->dropin_paths, q);
(void) mkdir_p(p, 0755);
r = write_string_file_atomic_label(q, prefixed);
if (r < 0)
return r;
strv_sort(u->dropin_paths);
r = strv_push(&u->dropin_paths, q);
if (r < 0)
return r;
q = NULL;
strv_uniq(u->dropin_paths);
u->dropin_mtime = now(CLOCK_REALTIME);
@ -3398,7 +3425,7 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n
}
int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
_cleanup_free_ char *ndata = NULL;
const char *ndata;
assert(u);
assert(name);
@ -3410,9 +3437,7 @@ int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *
if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
return 0;
ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
if (!ndata)
return -ENOMEM;
ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
return unit_write_drop_in(u, mode, name, ndata);
}
@ -3440,24 +3465,50 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
}
int unit_make_transient(Unit *u) {
FILE *f;
char *path;
assert(u);
if (!UNIT_VTABLE(u)->can_transient)
return -EOPNOTSUPP;
u->load_state = UNIT_STUB;
u->load_error = 0;
u->transient = true;
path = strjoin(u->manager->lookup_paths.transient, "/", u->id, NULL);
if (!path)
return -ENOMEM;
/* Let's open the file we'll write the transient settings into. This file is kept open as long as we are
* creating the transient, and is closed in unit_load(), as soon as we start loading the file. */
RUN_WITH_UMASK(0022)
f = fopen(path, "we");
if (!f) {
free(path);
return -errno;
}
if (u->transient_file)
fclose(u->transient_file);
u->transient_file = f;
free(u->fragment_path);
u->fragment_path = path;
u->fragment_path = mfree(u->fragment_path);
u->source_path = mfree(u->source_path);
u->dropin_paths = strv_free(u->dropin_paths);
u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
u->load_state = UNIT_STUB;
u->load_error = 0;
u->transient = true;
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
unit_add_to_load_queue(u);
fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n",
u->transient_file);
return 0;
}

View file

@ -95,6 +95,9 @@ struct Unit {
usec_t source_mtime;
usec_t dropin_mtime;
/* If this is a transient unit we are currently writing, this is where we are writing it to */
FILE *transient_file;
/* If there is something to do with this unit, then this is the installed job for it */
Job *job;

View file

@ -44,15 +44,6 @@ typedef enum PullJobState {
#define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
typedef enum PullJobCompression {
PULL_JOB_UNCOMPRESSED,
PULL_JOB_XZ,
PULL_JOB_GZIP,
PULL_JOB_BZIP2,
_PULL_JOB_COMPRESSION_MAX,
_PULL_JOB_COMPRESSION_INVALID = -1,
} PullJobCompression;
struct PullJob {
PullJobState state;
int error;

View file

@ -38,6 +38,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, ESHUTDOWN),
SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_GENERATED, EADDRNOTAVAIL),
SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_LINKED, ELOOP),
SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM),
SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED),

View file

@ -34,6 +34,8 @@
#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive"
#define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked"
#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated"
#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked"
#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable"
#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation"
#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"

View file

@ -1145,8 +1145,7 @@ _public_ int sd_event_add_signal(
int r;
assert_return(e, -EINVAL);
assert_return(sig > 0, -EINVAL);
assert_return(sig < _NSIG, -EINVAL);
assert_return(SIGNAL_VALID(sig), -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
@ -2200,7 +2199,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
if (_unlikely_(n != sizeof(si)))
return -EIO;
assert(si.ssi_signo < _NSIG);
assert(SIGNAL_VALID(si.ssi_signo));
read_one = true;

View file

@ -24,6 +24,7 @@
#ifdef HAVE_XKBCOMMON
#include <xkbcommon/xkbcommon.h>
#include <dlfcn.h>
#endif
#include "sd-bus.h"
@ -1101,6 +1102,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
}
#ifdef HAVE_XKBCOMMON
_printf_(3, 0)
static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
const char *fmt;
@ -1109,7 +1111,24 @@ static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char
log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
}
#define LOAD_SYMBOL(symbol, dl, name) \
({ \
(symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \
(symbol) ? 0 : -EOPNOTSUPP; \
})
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
/* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge
* after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function
* pointers to the shared library are below: */
struct xkb_context* (*symbol_xkb_context_new)(enum xkb_context_flags flags) = NULL;
void (*symbol_xkb_context_unref)(struct xkb_context *context) = NULL;
void (*symbol_xkb_context_set_log_fn)(struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args)) = NULL;
struct xkb_keymap* (*symbol_xkb_keymap_new_from_names)(struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags) = NULL;
void (*symbol_xkb_keymap_unref)(struct xkb_keymap *keymap) = NULL;
const struct xkb_rule_names rmlvo = {
.model = model,
.layout = layout,
@ -1118,35 +1137,68 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
};
struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL;
void *dl;
int r;
/* compile keymap from RMLVO information to check out its validity */
/* Compile keymap from RMLVO information to check out its validity */
ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
dl = dlopen("libxkbcommon.so.0", RTLD_LAZY);
if (!dl)
return -EOPNOTSUPP;
r = LOAD_SYMBOL(symbol_xkb_context_new, dl, "xkb_context_new");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_context_unref, dl, "xkb_context_unref");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_context_set_log_fn, dl, "xkb_context_set_log_fn");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_keymap_new_from_names, dl, "xkb_keymap_new_from_names");
if (r < 0)
goto finish;
r = LOAD_SYMBOL(symbol_xkb_keymap_unref, dl, "xkb_keymap_unref");
if (r < 0)
goto finish;
ctx = symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
if (!ctx) {
r = -ENOMEM;
goto exit;
goto finish;
}
xkb_context_set_log_fn(ctx, log_xkb);
symbol_xkb_context_set_log_fn(ctx, log_xkb);
km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
km = symbol_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!km) {
r = -EINVAL;
goto exit;
goto finish;
}
r = 0;
exit:
xkb_keymap_unref(km);
xkb_context_unref(ctx);
finish:
if (symbol_xkb_keymap_unref && km)
symbol_xkb_keymap_unref(km);
if (symbol_xkb_context_unref && ctx)
symbol_xkb_context_unref(ctx);
(void) dlclose(dl);
return r;
}
#else
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
return 0;
}
#endif
static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
@ -1203,7 +1255,11 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
if (r < 0) {
log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
strempty(model), strempty(layout), strempty(variant), strempty(options));
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing");
if (r == -EOPNOTSUPP)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid.");
}
if (free_and_strdup(&c->x11_layout, layout) < 0 ||

View file

@ -28,6 +28,7 @@
#include "logind-session-device.h"
#include "logind-session.h"
#include "logind.h"
#include "signal-util.h"
#include "strv.h"
#include "util.h"
@ -300,7 +301,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
}
if (signo <= 0 || signo >= _NSIG)
if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = bus_verify_polkit_async(

View file

@ -25,6 +25,7 @@
#include "formats-util.h"
#include "logind-user.h"
#include "logind.h"
#include "signal-util.h"
#include "strv.h"
#include "user-util.h"
@ -222,7 +223,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
if (r < 0)
return r;
if (signo <= 0 || signo >= _NSIG)
if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = user_kill(u, signo);

View file

@ -46,6 +46,7 @@
#include "mkdir.h"
#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "user-util.h"
@ -166,7 +167,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
}
if (signo <= 0 || signo >= _NSIG)
if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = bus_verify_polkit_async(

View file

@ -2338,6 +2338,50 @@ static int set_limit(int argc, char *argv[], void *userdata) {
return 0;
}
static int clean_images(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
uint64_t usage, total = 0;
char fb[FORMAT_BYTES_MAX];
sd_bus *bus = userdata;
const char *name;
unsigned c = 0;
int r;
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"CleanPool",
&error,
&reply,
"s", arg_all ? "all" : "hidden");
if (r < 0)
return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, 'a', "(st)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
log_info("Removed image '%s'. Freed exclusive disk space: %s",
name, format_bytes(fb, sizeof(fb), usage));
total += usage;
c++;
}
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
log_info("Removed %u images in total. Total freed exclusive disk space %s.",
c, format_bytes(fb, sizeof(fb), total));
return 0;
}
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@ -2396,6 +2440,7 @@ static int help(int argc, char *argv[], void *userdata) {
" read-only NAME [BOOL] Mark or unmark image read-only\n"
" remove NAME... Remove an image\n"
" set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n"
" clean Remove hidden (or all) images\n"
"Image Transfer Commands:\n"
" pull-tar URL [NAME] Download a TAR container image\n"
" pull-raw URL [NAME] Download a RAW container or VM image\n"
@ -2635,6 +2680,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
{ "set-limit", 2, 3, 0, set_limit },
{ "clean", VERB_ANY, 1, 0, clean_images },
{}
};

View file

@ -802,6 +802,93 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata,
return bus_image_method_mark_read_only(message, i, error);
}
static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
enum {
REMOVE_ALL,
REMOVE_HIDDEN,
} mode;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(image_hashmap_freep) Hashmap *images = NULL;
Manager *m = userdata;
Image *image;
const char *mm;
Iterator i;
int r;
assert(message);
r = sd_bus_message_read(message, "s", &mm);
if (r < 0)
return r;
if (streq(mm, "all"))
mode = REMOVE_ALL;
else if (streq(mm, "hidden"))
mode = REMOVE_HIDDEN;
else
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm);
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
"org.freedesktop.machine1.manage-machines",
NULL,
false,
UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Will call us back */
images = hashmap_new(&string_hash_ops);
if (!images)
return -ENOMEM;
r = image_discover(images);
if (r < 0)
return r;
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
r = sd_bus_message_open_container(reply, 'a', "(st)");
if (r < 0)
return r;
HASHMAP_FOREACH(image, images, i) {
/* We can't remove vendor images (i.e. those in /usr) */
if (IMAGE_IS_VENDOR(image))
continue;
if (IMAGE_IS_HOST(image))
continue;
if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
continue;
r = image_remove(image);
if (r == -EBUSY) /* keep images that are currently being used. */
continue;
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name);
r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive);
if (r < 0)
return r;
}
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
return sd_bus_send(NULL, reply, NULL);
}
static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
uint64_t limit;
@ -1144,6 +1231,7 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),

View file

@ -30,6 +30,8 @@
#include "string-util.h"
#include "unaligned.h"
#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
@ -127,7 +129,7 @@ static int lldp_make_packet(
h = (struct ether_header*) packet;
h->ether_type = htobe16(ETHERTYPE_LLDP);
memcpy(h->ether_dhost, &(struct ether_addr) { SD_LLDP_MULTICAST_ADDR }, ETH_ALEN);
memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN);
memcpy(h->ether_shost, hwaddr, ETH_ALEN);
p = (uint8_t*) packet + sizeof(struct ether_header);
@ -199,7 +201,7 @@ static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size)
.ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
.ll.sll_addr = SD_LLDP_MULTICAST_ADDR,
.ll.sll_addr = LLDP_MULTICAST_ADDR,
};
_cleanup_close_ int fd = -1;

View file

@ -52,8 +52,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
int r;
if (section) {
route = hashmap_get(network->routes_by_section,
UINT_TO_PTR(section));
route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section));
if (route) {
*ret = route;
route = NULL;
@ -67,16 +66,18 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
return r;
route->protocol = RTPROT_STATIC;
route->network = network;
LIST_PREPEND(routes, network->static_routes, route);
if (section) {
r = hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route);
if (r < 0)
return r;
route->section = section;
hashmap_put(network->routes_by_section,
UINT_TO_PTR(route->section), route);
}
LIST_PREPEND(routes, network->static_routes, route);
route->network = network;
*ret = route;
route = NULL;

View file

@ -230,7 +230,6 @@ static void test_dnssec_verify_rrset2(void) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
DnssecResult result;
int r;
nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
assert_se(nsec);

View file

@ -17,14 +17,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#warning "Temporary work-around for broken glibc vs. linux kernel header definitions"
#warning "This really should be removed sooner rather than later, when this is fixed upstream"
#define _NET_IF_H 1
#include <alloca.h>
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <net/if.h>
#include <stddef.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/if.h>
#ifndef IFNAMSIZ
#undef _NET_IF_H
/* Let's make sure to include this one, too, if IFNAMSIZ isn't defined yet, as it is for kernels <= 4.2 */
#include <net/if.h>
#endif
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>

File diff suppressed because it is too large Load diff

View file

@ -54,6 +54,8 @@ enum UnitFileState {
UNIT_FILE_STATIC,
UNIT_FILE_DISABLED,
UNIT_FILE_INDIRECT,
UNIT_FILE_GENERATED,
UNIT_FILE_TRANSIENT,
UNIT_FILE_BAD,
_UNIT_FILE_STATE_MAX,
_UNIT_FILE_STATE_INVALID = -1
@ -126,17 +128,18 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_revert(UnitFileScope scope, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name);
int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret);
int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name);
int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
Hashmap* unit_file_list_free(Hashmap *h);

View file

@ -401,8 +401,7 @@ int image_remove(Image *i) {
assert(i);
if (path_equal(i->path, "/") ||
path_startswith(i->path, "/usr"))
if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
settings = image_settings_path(i);
@ -474,8 +473,7 @@ int image_rename(Image *i, const char *new_name) {
if (!image_name_is_valid(new_name))
return -EINVAL;
if (path_equal(i->path, "/") ||
path_startswith(i->path, "/usr"))
if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
settings = image_settings_path(i);
@ -642,8 +640,7 @@ int image_read_only(Image *i, bool b) {
int r;
assert(i);
if (path_equal(i->path, "/") ||
path_startswith(i->path, "/usr"))
if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
/* Make sure we don't interfere with a running nspawn */
@ -751,8 +748,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
int image_set_limit(Image *i, uint64_t referenced_max) {
assert(i);
if (path_equal(i->path, "/") ||
path_startswith(i->path, "/usr"))
if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
if (i->type != IMAGE_SUBVOLUME)

View file

@ -25,6 +25,8 @@
#include "hashmap.h"
#include "lockfile-util.h"
#include "macro.h"
#include "path-util.h"
#include "string-util.h"
#include "time-util.h"
typedef enum ImageType {
@ -75,3 +77,27 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
int image_name_lock(const char *name, int operation, LockFile *ret);
int image_set_limit(Image *i, uint64_t referenced_max);
static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
assert(i);
return i->name && i->name[0] == '.';
}
static inline bool IMAGE_IS_VENDOR(const struct Image *i) {
assert(i);
return i->path && path_startswith(i->path, "/usr");
}
static inline bool IMAGE_IS_HOST(const struct Image *i) {
assert(i);
if (i->name && streq(i->name, ".host"))
return true;
if (i->path && path_equal(i->path, "/"))
return true;
return false;
}

View file

@ -26,61 +26,66 @@
#include "install.h"
#include "log.h"
#include "macro.h"
#include "mkdir.h"
#include "path-lookup.h"
#include "path-util.h"
#include "rm-rf.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
int user_config_home(char **config_home) {
static int user_runtime_dir(char **ret, const char *suffix) {
const char *e;
char *r;
char *j;
assert(ret);
assert(suffix);
e = getenv("XDG_RUNTIME_DIR");
if (!e)
return -ENXIO;
j = strappend(e, suffix);
if (!j)
return -ENOMEM;
*ret = j;
return 0;
}
static int user_config_dir(char **ret, const char *suffix) {
const char *e;
char *j;
assert(ret);
e = getenv("XDG_CONFIG_HOME");
if (e) {
r = strappend(e, "/systemd/user");
if (!r)
return -ENOMEM;
*config_home = r;
return 1;
} else {
if (e)
j = strappend(e, suffix);
else {
const char *home;
home = getenv("HOME");
if (home) {
r = strappend(home, "/.config/systemd/user");
if (!r)
return -ENOMEM;
if (!home)
return -ENXIO;
*config_home = r;
return 1;
}
j = strjoin(home, "/.config", suffix, NULL);
}
if (!j)
return -ENOMEM;
*ret = j;
return 0;
}
int user_runtime_dir(char **runtime_dir) {
static int user_data_dir(char **ret, const char *suffix) {
const char *e;
char *r;
char *j;
e = getenv("XDG_RUNTIME_DIR");
if (e) {
r = strappend(e, "/systemd/user");
if (!r)
return -ENOMEM;
*runtime_dir = r;
return 1;
}
return 0;
}
static int user_data_home_dir(char **dir, const char *suffix) {
const char *e;
char *res;
assert(ret);
assert(suffix);
/* We don't treat /etc/xdg/systemd here as the spec
* suggests because we assume that that is a link to
@ -88,27 +93,33 @@ static int user_data_home_dir(char **dir, const char *suffix) {
e = getenv("XDG_DATA_HOME");
if (e)
res = strappend(e, suffix);
j = strappend(e, suffix);
else {
const char *home;
home = getenv("HOME");
if (home)
res = strjoin(home, "/.local/share", suffix, NULL);
else
return 0;
if (!home)
return -ENXIO;
j = strjoin(home, "/.local/share", suffix, NULL);
}
if (!res)
if (!j)
return -ENOMEM;
*dir = res;
return 0;
*ret = j;
return 1;
}
static char** user_dirs(
const char *persistent_config,
const char *runtime_config,
const char *generator,
const char *generator_early,
const char *generator_late) {
const char *generator_late,
const char *transient,
const char *persistent_control,
const char *runtime_control) {
const char * const config_unit_paths[] = {
USER_CONFIG_UNIT_PATH,
@ -116,8 +127,6 @@ static char** user_dirs(
NULL
};
const char * const runtime_unit_path = "/run/systemd/user";
const char * const data_unit_paths[] = {
"/usr/local/lib/systemd/user",
"/usr/local/share/systemd/user",
@ -128,8 +137,8 @@ static char** user_dirs(
};
const char *e;
_cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
_cleanup_free_ char *data_home = NULL;
_cleanup_free_ char **res = NULL;
char **tmp;
int r;
@ -143,12 +152,6 @@ static char** user_dirs(
* as data, and allow overriding as configuration.
*/
if (user_config_home(&config_home) < 0)
return NULL;
if (user_runtime_dir(&runtime_dir) < 0)
return NULL;
e = getenv("XDG_CONFIG_DIRS");
if (e) {
config_dirs = strv_split(e, ":");
@ -156,8 +159,8 @@ static char** user_dirs(
return NULL;
}
r = user_data_home_dir(&data_home, "/systemd/user");
if (r < 0)
r = user_data_dir(&data_home, "/systemd/user");
if (r < 0 && r != -ENXIO)
return NULL;
e = getenv("XDG_DATA_DIRS");
@ -171,35 +174,36 @@ static char** user_dirs(
return NULL;
/* Now merge everything we found. */
if (generator_early)
if (strv_extend(&res, generator_early) < 0)
return NULL;
if (strv_extend(&res, persistent_control) < 0)
return NULL;
if (config_home)
if (strv_extend(&res, config_home) < 0)
return NULL;
if (strv_extend(&res, runtime_control) < 0)
return NULL;
if (strv_extend(&res, transient) < 0)
return NULL;
if (strv_extend(&res, generator_early) < 0)
return NULL;
if (!strv_isempty(config_dirs))
if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
return NULL;
if (strv_extend(&res, persistent_config) < 0)
return NULL;
if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
return NULL;
if (runtime_dir)
if (strv_extend(&res, runtime_dir) < 0)
return NULL;
if (strv_extend(&res, runtime_unit_path) < 0)
if (strv_extend(&res, runtime_config) < 0)
return NULL;
if (generator)
if (strv_extend(&res, generator) < 0)
return NULL;
if (strv_extend(&res, generator) < 0)
return NULL;
if (data_home)
if (strv_extend(&res, data_home) < 0)
return NULL;
if (strv_extend(&res, data_home) < 0)
return NULL;
if (!strv_isempty(data_dirs))
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
@ -208,9 +212,8 @@ static char** user_dirs(
if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
return NULL;
if (generator_late)
if (strv_extend(&res, generator_late) < 0)
return NULL;
if (strv_extend(&res, generator_late) < 0)
return NULL;
if (path_strv_make_absolute_cwd(res) < 0)
return NULL;
@ -220,58 +223,299 @@ static char** user_dirs(
return tmp;
}
char **generator_paths(ManagerRunningAs running_as) {
if (running_as == MANAGER_USER)
return strv_new("/run/systemd/user-generators",
"/etc/systemd/user-generators",
"/usr/local/lib/systemd/user-generators",
USER_GENERATOR_PATH,
NULL);
else
return strv_new("/run/systemd/system-generators",
"/etc/systemd/system-generators",
"/usr/local/lib/systemd/system-generators",
SYSTEM_GENERATOR_PATH,
NULL);
static int acquire_generator_dirs(
UnitFileScope scope,
char **generator,
char **generator_early,
char **generator_late) {
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
const char *prefix;
assert(generator);
assert(generator_early);
assert(generator_late);
switch (scope) {
case UNIT_FILE_SYSTEM:
prefix = "/run/systemd/";
break;
case UNIT_FILE_USER: {
const char *e;
e = getenv("XDG_RUNTIME_DIR");
if (!e)
return -ENXIO;
prefix = strjoina(e, "/systemd/", NULL);
break;
}
case UNIT_FILE_GLOBAL:
return -EOPNOTSUPP;
default:
assert_not_reached("Hmm, unexpected scope value.");
}
x = strappend(prefix, "generator");
if (!x)
return -ENOMEM;
y = strappend(prefix, "generator.early");
if (!y)
return -ENOMEM;
z = strappend(prefix, "generator.late");
if (!z)
return -ENOMEM;
*generator = x;
*generator_early = y;
*generator_late = z;
x = y = z = NULL;
return 0;
}
static int acquire_transient_dir(UnitFileScope scope, char **ret) {
assert(ret);
switch (scope) {
case UNIT_FILE_SYSTEM: {
char *transient;
transient = strdup("/run/systemd/transient");
if (!transient)
return -ENOMEM;
*ret = transient;
return 0;
}
case UNIT_FILE_USER:
return user_runtime_dir(ret, "/systemd/transient");
case UNIT_FILE_GLOBAL:
return -EOPNOTSUPP;
default:
assert_not_reached("Hmm, unexpected scope value.");
}
}
static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
_cleanup_free_ char *a = NULL, *b = NULL;
int r;
assert(persistent);
assert(runtime);
switch (scope) {
case UNIT_FILE_SYSTEM:
a = strdup(SYSTEM_CONFIG_UNIT_PATH);
b = strdup("/run/systemd/system");
break;
case UNIT_FILE_GLOBAL:
a = strdup(USER_CONFIG_UNIT_PATH);
b = strdup("/run/systemd/user");
break;
case UNIT_FILE_USER:
r = user_config_dir(&a, "/systemd/user");
if (r < 0)
return r;
r = user_runtime_dir(runtime, "/systemd/user");
if (r < 0)
return r;
*persistent = a;
a = NULL;
return 0;
default:
assert_not_reached("Hmm, unexpected scope value.");
}
if (!a || !b)
return -ENOMEM;
*persistent = a;
*runtime = b;
a = b = NULL;
return 0;
}
static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
_cleanup_free_ char *a = NULL;
int r;
assert(persistent);
assert(runtime);
switch (scope) {
case UNIT_FILE_SYSTEM: {
_cleanup_free_ char *b = NULL;
a = strdup("/etc/systemd/system.control");
if (!a)
return -ENOMEM;
b = strdup("/run/systemd/system.control");
if (!b)
return -ENOMEM;
*runtime = b;
b = NULL;
break;
}
case UNIT_FILE_USER:
r = user_config_dir(&a, "/systemd/system.control");
if (r < 0)
return r;
r = user_runtime_dir(runtime, "/systemd/system.control");
if (r < 0)
return r;
break;
case UNIT_FILE_GLOBAL:
return -EOPNOTSUPP;
default:
assert_not_reached("Hmm, unexpected scope value.");
}
*persistent = a;
a = NULL;
return 0;
}
static int patch_root_prefix(char **p, const char *root_dir) {
char *c;
assert(p);
if (!*p)
return 0;
c = prefix_root(root_dir, *p);
if (!c)
return -ENOMEM;
free(*p);
*p = c;
return 0;
}
static int patch_root_prefix_strv(char **l, const char *root_dir) {
char **i;
int r;
if (!root_dir)
return 0;
STRV_FOREACH(i, l) {
r = patch_root_prefix(i, root_dir);
if (r < 0)
return r;
}
return 0;
}
int lookup_paths_init(
LookupPaths *p,
ManagerRunningAs running_as,
bool personal,
const char *root_dir,
const char *generator,
const char *generator_early,
const char *generator_late) {
UnitFileScope scope,
LookupPathsFlags flags,
const char *root_dir) {
const char *e;
_cleanup_free_ char
*root = NULL,
*persistent_config = NULL, *runtime_config = NULL,
*generator = NULL, *generator_early = NULL, *generator_late = NULL,
*transient = NULL,
*persistent_control = NULL, *runtime_control = NULL;
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
char **l = NULL;
const char *e;
int r;
assert(p);
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
/* First priority is whatever has been passed to us via env
* vars */
if (!isempty(root_dir) && !path_equal(root_dir, "/")) {
if (scope == UNIT_FILE_USER)
return -EINVAL;
r = is_dir(root_dir, true);
if (r < 0)
return r;
if (r == 0)
return -ENOTDIR;
root = strdup(root_dir);
if (!root)
return -ENOMEM;
}
r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
if (r < 0 && r != -ENXIO)
return r;
if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
return r;
}
r = acquire_transient_dir(scope, &transient);
if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
return r;
r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
return r;
/* First priority is whatever has been passed to us via env vars */
e = getenv("SYSTEMD_UNIT_PATH");
if (e) {
if (endswith(e, ":")) {
e = strndupa(e, strlen(e) - 1);
const char *k;
k = endswith(e, ":");
if (k) {
e = strndupa(e, k - e);
append = true;
}
/* FIXME: empty components in other places should be
* rejected. */
r = path_split_and_make_absolute(e, &p->unit_path);
r = path_split_and_make_absolute(e, &l);
if (r < 0)
return r;
} else
p->unit_path = NULL;
l = NULL;
if (!p->unit_path || append) {
if (!l || append) {
/* Let's figure something out. */
_cleanup_strv_free_ char **unit_path;
_cleanup_strv_free_ char **add = NULL;
/* For the user units we include share/ in the search
* path in order to comply with the XDG basedir spec.
@ -279,17 +523,45 @@ int lookup_paths_init(
* we include /lib in the search path for the system
* stuff but avoid it for user stuff. */
if (running_as == MANAGER_USER) {
if (personal)
unit_path = user_dirs(generator, generator_early, generator_late);
else
unit_path = strv_new(
switch (scope) {
case UNIT_FILE_SYSTEM:
add = strv_new(
/* If you modify this you also want to modify
* systemdsystemunitpath= in systemd.pc.in! */
STRV_IFNOTNULL(persistent_control),
STRV_IFNOTNULL(runtime_control),
STRV_IFNOTNULL(transient),
STRV_IFNOTNULL(generator_early),
persistent_config,
SYSTEM_CONFIG_UNIT_PATH,
"/etc/systemd/system",
runtime_config,
"/run/systemd/system",
STRV_IFNOTNULL(generator),
"/usr/local/lib/systemd/system",
SYSTEM_DATA_UNIT_PATH,
"/usr/lib/systemd/system",
#ifdef HAVE_SPLIT_USR
"/lib/systemd/system",
#endif
STRV_IFNOTNULL(generator_late),
NULL);
break;
case UNIT_FILE_GLOBAL:
add = strv_new(
/* If you modify this you also want to modify
* systemduserunitpath= in systemd.pc.in, and
* the arrays in user_dirs() above! */
STRV_IFNOTNULL(persistent_control),
STRV_IFNOTNULL(runtime_control),
STRV_IFNOTNULL(transient),
STRV_IFNOTNULL(generator_early),
persistent_config,
USER_CONFIG_UNIT_PATH,
"/etc/systemd/user",
runtime_config,
"/run/systemd/user",
STRV_IFNOTNULL(generator),
"/usr/local/lib/systemd/user",
@ -299,143 +571,251 @@ int lookup_paths_init(
"/usr/share/systemd/user",
STRV_IFNOTNULL(generator_late),
NULL);
} else
unit_path = strv_new(
/* If you modify this you also want to modify
* systemdsystemunitpath= in systemd.pc.in! */
STRV_IFNOTNULL(generator_early),
SYSTEM_CONFIG_UNIT_PATH,
"/etc/systemd/system",
"/run/systemd/system",
STRV_IFNOTNULL(generator),
"/usr/local/lib/systemd/system",
SYSTEM_DATA_UNIT_PATH,
"/usr/lib/systemd/system",
#ifdef HAVE_SPLIT_USR
"/lib/systemd/system",
#endif
STRV_IFNOTNULL(generator_late),
NULL);
break;
if (!unit_path)
case UNIT_FILE_USER:
add = user_dirs(persistent_config, runtime_config,
generator, generator_early, generator_late,
transient,
persistent_config, runtime_control);
break;
default:
assert_not_reached("Hmm, unexpected scope?");
}
if (!add)
return -ENOMEM;
r = strv_extend_strv(&p->unit_path, unit_path, false);
if (r < 0)
return r;
if (l) {
r = strv_extend_strv(&l, add, false);
if (r < 0)
return r;
} else {
l = add;
add = NULL;
}
}
if (!path_strv_resolve_uniq(p->unit_path, root_dir))
r = patch_root_prefix(&persistent_config, root);
if (r < 0)
return r;
r = patch_root_prefix(&runtime_config, root);
if (r < 0)
return r;
r = patch_root_prefix(&generator, root);
if (r < 0)
return r;
r = patch_root_prefix(&generator_early, root);
if (r < 0)
return r;
r = patch_root_prefix(&generator_late, root);
if (r < 0)
return r;
r = patch_root_prefix(&transient, root);
if (r < 0)
return r;
r = patch_root_prefix(&persistent_control, root);
if (r < 0)
return r;
r = patch_root_prefix(&runtime_control, root);
if (r < 0)
return r;
r = patch_root_prefix_strv(l, root);
if (r < 0)
return -ENOMEM;
if (!strv_isempty(p->unit_path)) {
_cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
if (!t)
return -ENOMEM;
log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
} else {
log_debug("Ignoring unit files.");
p->unit_path = strv_free(p->unit_path);
}
p->search_path = strv_uniq(l);
l = NULL;
if (running_as == MANAGER_SYSTEM) {
#ifdef HAVE_SYSV_COMPAT
/* /etc/init.d/ compatibility does not matter to users */
p->persistent_config = persistent_config;
p->runtime_config = runtime_config;
persistent_config = runtime_config = NULL;
e = getenv("SYSTEMD_SYSVINIT_PATH");
if (e) {
r = path_split_and_make_absolute(e, &p->sysvinit_path);
if (r < 0)
return r;
} else
p->sysvinit_path = NULL;
p->generator = generator;
p->generator_early = generator_early;
p->generator_late = generator_late;
generator = generator_early = generator_late = NULL;
if (strv_isempty(p->sysvinit_path)) {
strv_free(p->sysvinit_path);
p->transient = transient;
transient = NULL;
p->sysvinit_path = strv_new(
SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
NULL);
if (!p->sysvinit_path)
return -ENOMEM;
}
p->persistent_control = persistent_control;
p->runtime_control = runtime_control;
persistent_control = runtime_control = NULL;
e = getenv("SYSTEMD_SYSVRCND_PATH");
if (e) {
r = path_split_and_make_absolute(e, &p->sysvrcnd_path);
if (r < 0)
return r;
} else
p->sysvrcnd_path = NULL;
if (strv_isempty(p->sysvrcnd_path)) {
strv_free(p->sysvrcnd_path);
p->sysvrcnd_path = strv_new(
SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
NULL);
if (!p->sysvrcnd_path)
return -ENOMEM;
}
if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
return -ENOMEM;
if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
return -ENOMEM;
if (!strv_isempty(p->sysvinit_path)) {
_cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
if (!t)
return -ENOMEM;
log_debug("Looking for SysV init scripts in:\n\t%s", t);
} else {
log_debug("Ignoring SysV init scripts.");
p->sysvinit_path = strv_free(p->sysvinit_path);
}
if (!strv_isempty(p->sysvrcnd_path)) {
_cleanup_free_ char *t =
strv_join(p->sysvrcnd_path, "\n\t");
if (!t)
return -ENOMEM;
log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
} else {
log_debug("Ignoring SysV rcN.d links.");
p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
}
#else
log_debug("SysV init scripts and rcN.d links support disabled");
#endif
}
p->root_dir = root;
root = NULL;
return 0;
}
void lookup_paths_free(LookupPaths *p) {
if (!p)
return;
p->search_path = strv_free(p->search_path);
p->persistent_config = mfree(p->persistent_config);
p->runtime_config = mfree(p->runtime_config);
p->generator = mfree(p->generator);
p->generator_early = mfree(p->generator_early);
p->generator_late = mfree(p->generator_late);
p->transient = mfree(p->transient);
p->persistent_control = mfree(p->persistent_control);
p->runtime_control = mfree(p->runtime_control);
p->root_dir = mfree(p->root_dir);
}
int lookup_paths_reduce(LookupPaths *p) {
_cleanup_free_ struct stat *stats = NULL;
size_t n_stats = 0, allocated = 0;
unsigned c = 0;
int r;
assert(p);
p->unit_path = strv_free(p->unit_path);
/* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
* the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
* we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
* account when following symlinks. When we have no root path set this restriction does not apply however. */
#ifdef HAVE_SYSV_COMPAT
p->sysvinit_path = strv_free(p->sysvinit_path);
p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
#endif
if (!p->search_path)
return 0;
while (p->search_path[c]) {
struct stat st;
unsigned k;
if (p->root_dir)
r = lstat(p->search_path[c], &st);
else
r = stat(p->search_path[c], &st);
if (r < 0) {
if (errno == ENOENT)
goto remove_item;
/* If something we don't grok happened, let's better leave it in. */
log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]);
c++;
continue;
}
for (k = 0; k < n_stats; k++) {
if (stats[k].st_dev == st.st_dev &&
stats[k].st_ino == st.st_ino)
break;
}
if (k < n_stats) /* Is there already an entry with the same device/inode? */
goto remove_item;
if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
return -ENOMEM;
stats[n_stats++] = st;
c++;
continue;
remove_item:
free(p->search_path[c]);
memmove(p->search_path + c,
p->search_path + c + 1,
(strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
}
if (strv_isempty(p->search_path)) {
log_debug("Ignoring unit files.");
p->search_path = strv_free(p->search_path);
} else {
_cleanup_free_ char *t;
t = strv_join(p->search_path, "\n\t");
if (!t)
return -ENOMEM;
log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
}
return 0;
}
int lookup_paths_init_from_scope(LookupPaths *paths,
UnitFileScope scope,
const char *root_dir) {
assert(paths);
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
int lookup_paths_mkdir_generator(LookupPaths *p) {
int r, q;
zero(*paths);
assert(p);
return lookup_paths_init(paths,
scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
scope == UNIT_FILE_USER,
root_dir,
NULL, NULL, NULL);
if (!p->generator || !p->generator_early || !p->generator_late)
return -EINVAL;
r = mkdir_p_label(p->generator, 0755);
q = mkdir_p_label(p->generator_early, 0755);
if (q < 0 && r >= 0)
r = q;
q = mkdir_p_label(p->generator_late, 0755);
if (q < 0 && r >= 0)
r = q;
return r;
}
void lookup_paths_trim_generator(LookupPaths *p) {
assert(p);
/* Trim empty dirs */
if (p->generator)
(void) rmdir(p->generator);
if (p->generator_early)
(void) rmdir(p->generator_early);
if (p->generator_late)
(void) rmdir(p->generator_late);
}
void lookup_paths_flush_generator(LookupPaths *p) {
assert(p);
/* Flush the generated unit files in full */
if (p->generator)
(void) rm_rf(p->generator, REMOVE_ROOT);
if (p->generator_early)
(void) rm_rf(p->generator_early, REMOVE_ROOT);
if (p->generator_late)
(void) rm_rf(p->generator_late, REMOVE_ROOT);
}
char **generator_binary_paths(UnitFileScope scope) {
switch (scope) {
case UNIT_FILE_SYSTEM:
return strv_new("/run/systemd/system-generators",
"/etc/systemd/system-generators",
"/usr/local/lib/systemd/system-generators",
SYSTEM_GENERATOR_PATH,
NULL);
case UNIT_FILE_GLOBAL:
case UNIT_FILE_USER:
return strv_new("/run/systemd/user-generators",
"/etc/systemd/user-generators",
"/usr/local/lib/systemd/user-generators",
USER_GENERATOR_PATH,
NULL);
default:
assert_not_reached("Hmm, unexpected scope.");
}
}

View file

@ -20,41 +20,57 @@
***/
#include <stdbool.h>
#include "macro.h"
typedef struct LookupPaths {
char **unit_path;
#ifdef HAVE_SYSV_COMPAT
char **sysvinit_path;
char **sysvrcnd_path;
#endif
} LookupPaths;
typedef enum ManagerRunningAs {
MANAGER_SYSTEM,
MANAGER_USER,
_MANAGER_RUNNING_AS_MAX,
_MANAGER_RUNNING_AS_INVALID = -1
} ManagerRunningAs;
int user_config_home(char **config_home);
int user_runtime_dir(char **runtime_dir);
char **generator_paths(ManagerRunningAs running_as);
int lookup_paths_init(LookupPaths *p,
ManagerRunningAs running_as,
bool personal,
const char *root_dir,
const char *generator,
const char *generator_early,
const char *generator_late);
typedef struct LookupPaths LookupPaths;
#include "install.h"
#include "macro.h"
int lookup_paths_init_from_scope(LookupPaths *paths,
UnitFileScope scope,
const char *root_dir);
typedef enum LookupPathsFlags {
LOOKUP_PATHS_EXCLUDE_GENERATED = 1,
} LookupPathsFlags;
struct LookupPaths {
/* Where we look for unit files. This includes the individual special paths below, but also any vendor
* supplied, static unit file paths. */
char **search_path;
/* Where we shall create or remove our installation symlinks, aka "configuration", and where the user/admin
* shall place his own unit files. */
char *persistent_config;
char *runtime_config;
/* Where to place generated unit files (i.e. those a "generator" tool generated). Note the special semantics of
* this directory: the generators are flushed each time a "systemctl daemon-reload" is issued. The user should
* not alter these directories directly. */
char *generator;
char *generator_early;
char *generator_late;
/* Where to place transient unit files (i.e. those created dynamically via the bus API). Note the special
* semantics of this directory: all units created transiently have their unit files removed as the transient
* unit is unloaded. The user should not alter this directory directly. */
char *transient;
/* Where the snippets created by "systemctl set-property" are placed. Note that for transient units, the
* snippets are placed in the transient directory though (see above). The user should not alter this directory
* directly. */
char *persistent_control;
char *runtime_control;
/* The root directory prepended to all items above, or NULL */
char *root_dir;
};
int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
int lookup_paths_reduce(LookupPaths *p);
int lookup_paths_mkdir_generator(LookupPaths *p);
void lookup_paths_trim_generator(LookupPaths *p);
void lookup_paths_flush_generator(LookupPaths *p);
void lookup_paths_free(LookupPaths *p);
#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free)
char **generator_binary_paths(UnitFileScope scope);

33
src/shared/tests.c Normal file
View file

@ -0,0 +1,33 @@
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdlib.h>
#include <util.h>
#include "tests.h"
char* setup_fake_runtime_dir(void) {
char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
assert_se(mkdtemp(t));
assert_se(setenv("XDG_RUNTIME_DIR", t, 1) >= 0);
assert_se(p = strdup(t));
return p;
}

22
src/shared/tests.h Normal file
View file

@ -0,0 +1,22 @@
#pragma once
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
char* setup_fake_runtime_dir(void);

View file

@ -1993,7 +1993,7 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha
if (changes[i].type == UNIT_FILE_SYMLINK)
log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
else
log_info("Removed symlink %s.", changes[i].path);
log_info("Removed %s.", changes[i].path);
}
}
@ -2295,7 +2295,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
assert(unit_name);
assert(unit_path);
STRV_FOREACH(p, lp->unit_path) {
STRV_FOREACH(p, lp->search_path) {
_cleanup_free_ char *path;
path = path_join(arg_root, *p, unit_name);
@ -2395,7 +2395,7 @@ static int unit_find_paths(
}
if (dropin_paths) {
r = unit_file_find_dropin_paths(lp->unit_path, NULL, names, &dropins);
r = unit_file_find_dropin_paths(lp->search_path, NULL, names, &dropins);
if (r < 0)
return r;
}
@ -3136,7 +3136,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
return r;
if (a == ACTION_REBOOT && argc > 1) {
r = update_reboot_param_file(argv[1]);
r = update_reboot_parameter_and_warn(argv[1]);
if (r < 0)
return r;
@ -4780,34 +4780,6 @@ static int show(int argc, char *argv[], void *userdata) {
return ret;
}
static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
int r;
assert(user_home);
assert(user_runtime);
assert(lp);
if (arg_scope == UNIT_FILE_USER) {
r = user_config_home(user_home);
if (r < 0)
return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
else if (r == 0)
return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
r = user_runtime_dir(user_runtime);
if (r < 0)
return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
else if (r == 0)
return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
}
r = lookup_paths_init_from_scope(lp, arg_scope, arg_root);
if (r < 0)
return log_error_errno(r, "Failed to query unit lookup paths: %m");
return 0;
}
static int cat_file(const char *filename, bool newline) {
_cleanup_close_ int fd;
@ -4826,8 +4798,6 @@ static int cat_file(const char *filename, bool newline) {
}
static int cat(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
char **name;
@ -4840,9 +4810,9 @@ static int cat(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
if (r < 0)
return r;
return log_error_errno(r, "Failed to determine unit paths: %m");
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@ -5253,8 +5223,10 @@ static int enable_sysv_units(const char *verb, char **args) {
int r = 0;
#if defined(HAVE_SYSV_COMPAT)
unsigned f = 0;
_cleanup_lookup_paths_free_ LookupPaths paths = {};
unsigned f = 0;
/* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
if (arg_scope != UNIT_FILE_SYSTEM)
return 0;
@ -5268,24 +5240,28 @@ static int enable_sysv_units(const char *verb, char **args) {
"is-enabled"))
return 0;
/* Processes all SysV units, and reshuffles the array so that
* afterwards only the native units remain */
r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
if (r < 0)
return r;
r = 0;
while (args[f]) {
const char *name;
const char *argv[] = {
ROOTLIBEXECDIR "/systemd-sysv-install",
NULL,
NULL,
NULL,
NULL,
};
_cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
bool found_native = false, found_sysv;
unsigned c = 1;
const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
char **k;
int j;
pid_t pid;
siginfo_t status;
const char *name;
unsigned c = 1;
pid_t pid;
int j;
name = args[f++];
@ -5295,21 +5271,13 @@ static int enable_sysv_units(const char *verb, char **args) {
if (path_is_absolute(name))
continue;
STRV_FOREACH(k, paths.unit_path) {
_cleanup_free_ char *path = NULL;
j = unit_file_exists(arg_scope, &paths, name);
if (j < 0 && !IN_SET(j, -ELOOP, -ESHUTDOWN, -EADDRNOTAVAIL))
return log_error_errno(j, "Failed to lookup unit file state: %m");
found_native = j != 0;
path = path_join(arg_root, *k, name);
if (!path)
return log_oom();
found_native = access(path, F_OK) >= 0;
if (found_native)
break;
}
/* If we have both a native unit and a SysV script,
* enable/disable them both (below); for is-enabled, prefer the
* native unit */
/* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
* prefer the native unit */
if (found_native && streq(verb, "is-enabled"))
continue;
@ -5323,9 +5291,9 @@ static int enable_sysv_units(const char *verb, char **args) {
continue;
if (found_native)
log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
else
log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
if (!isempty(arg_root))
argv[c++] = q = strappend("--root=", arg_root);
@ -5338,7 +5306,7 @@ static int enable_sysv_units(const char *verb, char **args) {
if (!l)
return log_oom();
log_info("Executing %s", l);
log_info("Executing: %s", l);
pid = fork();
if (pid < 0)
@ -5350,7 +5318,7 @@ static int enable_sysv_units(const char *verb, char **args) {
(void) reset_signal_mask();
execv(argv[0], (char**) argv);
log_error_errno(r, "Failed to execute %s: %m", argv[0]);
log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
}
@ -5372,9 +5340,11 @@ static int enable_sysv_units(const char *verb, char **args) {
}
} else if (status.si_status != 0)
return -EINVAL;
} else
return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
} else {
log_error("Unexpected waitid() result.");
return -EPROTO;
}
if (found_native)
continue;
@ -5445,8 +5415,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
/* If the operation was fully executed by the SysV compat,
* let's finish early */
/* If the operation was fully executed by the SysV compat, let's finish early */
if (strv_isempty(names))
return 0;
@ -5468,11 +5437,17 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
else if (streq(verb, "unmask"))
r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
else if (streq(verb, "revert"))
r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
else
assert_not_reached("Unknown verb");
if (r == -ESHUTDOWN)
return log_error_errno(r, "Unit file is masked.");
if (r == -EADDRNOTAVAIL)
return log_error_errno(r, "Unit file is transient or generated.");
if (r == -ELOOP)
return log_error_errno(r, "Refusing to operate on linked unit file.");
if (r < 0)
return log_error_errno(r, "Operation failed: %m");
@ -5484,7 +5459,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int expect_carries_install_info = false;
bool send_force = true, send_preset_mode = false;
bool send_runtime = true, send_force = true, send_preset_mode = false;
const char *method;
sd_bus *bus;
@ -5519,6 +5494,9 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
else if (streq(verb, "unmask")) {
method = "UnmaskUnitFiles";
send_force = false;
} else if (streq(verb, "revert")) {
method = "RevertUnitFiles";
send_runtime = send_force = false;
} else
assert_not_reached("Unknown verb");
@ -5542,9 +5520,11 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
return bus_log_create_error(r);
}
r = sd_bus_message_append(m, "b", arg_runtime);
if (r < 0)
return bus_log_create_error(r);
if (send_runtime) {
r = sd_bus_message_append(m, "b", arg_runtime);
if (r < 0)
return bus_log_create_error(r);
}
if (send_force) {
r = sd_bus_message_append(m, "b", arg_force);
@ -5639,6 +5619,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
if (r == -ESHUTDOWN)
return log_error_errno(r, "Unit file is masked.");
if (r == -EADDRNOTAVAIL)
return log_error_errno(r, "Unit file is transient or generated.");
if (r < 0)
return log_error_errno(r, "Can't add dependency: %m");
@ -5783,7 +5765,8 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
UNIT_FILE_ENABLED,
UNIT_FILE_ENABLED_RUNTIME,
UNIT_FILE_STATIC,
UNIT_FILE_INDIRECT))
UNIT_FILE_INDIRECT,
UNIT_FILE_GENERATED))
enabled = true;
if (!arg_quiet)
@ -5818,7 +5801,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
enabled = true;
if (!arg_quiet)
@ -5826,7 +5809,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
}
}
return !enabled;
return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int is_system_running(int argc, char *argv[], void *userdata) {
@ -5896,52 +5879,32 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
return 0;
}
static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
_cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
static int get_file_to_edit(
const LookupPaths *paths,
const char *name,
char **ret_path) {
_cleanup_free_ char *path = NULL, *run = NULL;
assert(name);
assert(ret_path);
switch (arg_scope) {
case UNIT_FILE_SYSTEM:
path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
if (arg_runtime)
run = path_join(arg_root, "/run/systemd/system/", name);
break;
case UNIT_FILE_GLOBAL:
path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
if (arg_runtime)
run = path_join(arg_root, "/run/systemd/user/", name);
break;
case UNIT_FILE_USER:
assert(user_home);
assert(user_runtime);
path = path_join(arg_root, user_home, name);
if (arg_runtime) {
path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
if (!path2)
return log_oom();
run = path_join(arg_root, user_runtime, name);
}
break;
default:
assert_not_reached("Invalid scope");
}
if (!path || (arg_runtime && !run))
path = strjoin(paths->persistent_config, "/", name, NULL);
if (!path)
return log_oom();
if (arg_runtime) {
run = strjoin(paths->runtime_config, name, NULL);
if (!run)
return log_oom();
}
if (arg_runtime) {
if (access(path, F_OK) >= 0) {
log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
return -EEXIST;
}
if (path2 && access(path2, F_OK) >= 0) {
log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
return -EEXIST;
}
*ret_path = run;
run = NULL;
} else {
@ -5952,7 +5915,12 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
return 0;
}
static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
static int unit_file_create_dropin(
const LookupPaths *paths,
const char *unit_name,
char **ret_new_path,
char **ret_tmp_path) {
char *tmp_new_path, *tmp_tmp_path, *ending;
int r;
@ -5961,7 +5929,7 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
assert(ret_tmp_path);
ending = strjoina(unit_name, ".d/override.conf");
r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
r = get_file_to_edit(paths, ending, &tmp_new_path);
if (r < 0)
return r;
@ -5978,10 +5946,9 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
}
static int unit_file_create_copy(
const LookupPaths *paths,
const char *unit_name,
const char *fragment_path,
const char *user_home,
const char *user_runtime,
char **ret_new_path,
char **ret_tmp_path) {
@ -5993,7 +5960,7 @@ static int unit_file_create_copy(
assert(ret_new_path);
assert(ret_tmp_path);
r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
r = get_file_to_edit(paths, unit_name, &tmp_new_path);
if (r < 0)
return r;
@ -6108,8 +6075,6 @@ static int run_editor(char **paths) {
}
static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
char **name;
int r;
@ -6117,7 +6082,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
assert(names);
assert(paths);
r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
if (r < 0)
return r;
@ -6137,9 +6102,9 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
}
if (arg_full)
r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
else
r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path);
if (r < 0)
return r;
@ -6324,6 +6289,8 @@ static void systemctl_help(void) {
" unmask NAME... Unmask one or more units\n"
" link PATH... Link one or more units files into\n"
" the search path\n"
" revert NAME... Revert one or more unit files to vendor\n"
" version\n"
" add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
" on specified one or more units\n"
" add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
@ -6992,7 +6959,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
}
if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
if (r < 0)
return r;
} else if (optind < argc) {
@ -7447,6 +7414,7 @@ static int systemctl_main(int argc, char *argv[]) {
{ "mask", 2, VERB_ANY, 0, enable_unit },
{ "unmask", 2, VERB_ANY, 0, enable_unit },
{ "link", 2, VERB_ANY, 0, enable_unit },
{ "revert", 2, VERB_ANY, 0, enable_unit },
{ "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
{ "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
{ "set-default", 2, 2, 0, set_default },
@ -7493,6 +7461,7 @@ static int start_with_fallback(void) {
}
static int halt_now(enum action a) {
int r;
/* The kernel will automaticall flush ATA disks and suchlike
* on reboot(), but the file systems need to be synce'd
@ -7519,9 +7488,14 @@ static int halt_now(enum action a) {
case ACTION_REBOOT: {
_cleanup_free_ char *param = NULL;
if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
r = read_one_line_file("/run/systemd/reboot-param", &param);
if (r < 0)
log_warning_errno(r, "Failed to read reboot parameter file: %m");
if (!isempty(param)) {
log_info("Rebooting with argument '%s'.", param);
(void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
}
log_info("Rebooting.");

View file

@ -33,20 +33,18 @@ _SD_BEGIN_DECLARATIONS;
typedef struct sd_lldp sd_lldp;
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
#define SD_LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
/* IEEE 802.3AB Clause 9: TLV Types */
enum {
SD_LLDP_TYPE_END = 0,
SD_LLDP_TYPE_CHASSIS_ID = 1,
SD_LLDP_TYPE_PORT_ID = 2,
SD_LLDP_TYPE_TTL = 3,
SD_LLDP_TYPE_PORT_DESCRIPTION = 4,
SD_LLDP_TYPE_SYSTEM_NAME = 5,
SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
SD_LLDP_TYPE_MGMT_ADDRESS = 8,
SD_LLDP_TYPE_PRIVATE = 127,
SD_LLDP_TYPE_END = 0,
SD_LLDP_TYPE_CHASSIS_ID = 1,
SD_LLDP_TYPE_PORT_ID = 2,
SD_LLDP_TYPE_TTL = 3,
SD_LLDP_TYPE_PORT_DESCRIPTION = 4,
SD_LLDP_TYPE_SYSTEM_NAME = 5,
SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
SD_LLDP_TYPE_MGMT_ADDRESS = 8,
SD_LLDP_TYPE_PRIVATE = 127,
};
/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */
@ -63,28 +61,28 @@ enum {
/* IEEE 802.3AB Clause 9.5.3: Port subtype */
enum {
SD_LLDP_PORT_SUBTYPE_RESERVED = 0,
SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
SD_LLDP_PORT_SUBTYPE_RESERVED = 0,
SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
};
enum {
SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3,
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4,
SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5,
SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6,
SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3,
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4,
SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5,
SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6,
SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
};
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1)
@ -104,13 +102,13 @@ enum {
#define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
enum {
SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3,
SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3,
SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
};
typedef enum sd_lldp_event {

View file

@ -729,14 +729,50 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
return 0;
}
static int acquire_search_path(const char *def, const char *envvar, char ***ret) {
_cleanup_strv_free_ char **l = NULL;
const char *e;
int r;
assert(def);
assert(envvar);
e = getenv(envvar);
if (e) {
r = path_split_and_make_absolute(e, &l);
if (r < 0)
return log_error_errno(r, "Failed to make $%s search path absolute: %m", envvar);
}
if (strv_isempty(l)) {
strv_free(l);
l = strv_new(def, NULL);
if (!l)
return log_oom();
}
if (!path_strv_resolve_uniq(l, NULL))
return log_oom();
*ret = l;
l = NULL;
return 0;
}
static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
_cleanup_strv_free_ char **sysvinit_path = NULL;
char **path;
int r;
assert(lp);
assert(all_services);
STRV_FOREACH(path, lp->sysvinit_path) {
r = acquire_search_path(SYSTEM_SYSVINIT_PATH, "SYSTEMD_SYSVINIT_PATH", &sysvinit_path);
if (r < 0)
return r;
STRV_FOREACH(path, sysvinit_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@ -770,11 +806,11 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
if (hashmap_contains(all_services, name))
continue;
r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL);
if (r < 0 && r != -ENOENT) {
r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name);
if (r < 0 && !IN_SET(r, -ELOOP, -ESHUTDOWN, -EADDRNOTAVAIL)) {
log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name);
continue;
} else if (r >= 0) {
} else if (r != 0) {
log_debug("Native unit for %s already exists, skipping.", name);
continue;
}
@ -806,6 +842,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
_cleanup_set_free_ Set *shutdown_services = NULL;
_cleanup_strv_free_ char **sysvrcnd_path = NULL;
SysvStub *service;
unsigned i;
Iterator j;
@ -814,7 +851,11 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
assert(lp);
STRV_FOREACH(p, lp->sysvrcnd_path) {
r = acquire_search_path(SYSTEM_SYSVRCND_PATH, "SYSTEMD_SYSVRCND_PATH", &sysvrcnd_path);
if (r < 0)
return r;
STRV_FOREACH(p, sysvrcnd_path) {
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
_cleanup_closedir_ DIR *d = NULL;
@ -963,7 +1004,7 @@ int main(int argc, char *argv[]) {
umask(0022);
r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
if (r < 0) {
log_error_errno(r, "Failed to find lookup paths: %m");
goto finish;

View file

@ -21,7 +21,9 @@
#include "macro.h"
#include "manager.h"
#include "rm-rf.h"
#include "test-helper.h"
#include "tests.h"
#include "unit.h"
static int test_cgroup_mask(void) {
@ -33,7 +35,7 @@ static int test_cgroup_mask(void) {
/* Prepare the manager. */
assert_se(set_unit_path(TEST_DIR) >= 0);
r = manager_new(MANAGER_USER, true, &m);
r = manager_new(UNIT_FILE_USER, true, &m);
if (r == -EPERM || r == -EACCES) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
@ -107,7 +109,11 @@ static int test_cgroup_mask(void) {
}
int main(int argc, char* argv[]) {
_cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
int rc = 0;
assert_se(runtime_dir = setup_fake_runtime_dir());
TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
return rc;
}

View file

@ -23,9 +23,12 @@
#include "bus-util.h"
#include "manager.h"
#include "rm-rf.h"
#include "test-helper.h"
#include "tests.h"
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
Manager *m = NULL;
Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
@ -34,9 +37,11 @@ int main(int argc, char *argv[]) {
Job *j;
int r;
assert_se(runtime_dir = setup_fake_runtime_dir());
/* prepare the test */
assert_se(set_unit_path(TEST_DIR) >= 0);
r = manager_new(MANAGER_USER, true, &m);
r = manager_new(UNIT_FILE_USER, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return EXIT_TEST_SKIP;

View file

@ -291,14 +291,14 @@ static void test_exec_spec_interpolation(Manager *m) {
test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
}
static int run_tests(ManagerRunningAs running_as, test_function_t *tests) {
static int run_tests(UnitFileScope scope, test_function_t *tests) {
test_function_t *test = NULL;
Manager *m = NULL;
int r;
assert_se(tests);
r = manager_new(running_as, true, &m);
r = manager_new(scope, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return EXIT_TEST_SKIP;
@ -366,9 +366,9 @@ int main(int argc, char *argv[]) {
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
r = run_tests(MANAGER_USER, user_tests);
r = run_tests(UNIT_FILE_USER, user_tests);
if (r != 0)
return r;
return run_tests(MANAGER_SYSTEM, system_tests);
return run_tests(UNIT_FILE_SYSTEM, system_tests);
}

View file

@ -30,6 +30,8 @@ static void test_basic_mask_and_enable(const char *root) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
log_set_max_level(LOG_DEBUG);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT);
@ -628,6 +630,57 @@ static void test_preset_and_list(const char *root) {
assert_se(got_yes && got_no);
}
static void test_revert(const char *root) {
const char *p;
UnitFileState state;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
assert(root);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT);
p = strjoina(root, "/usr/lib/systemd/system/xx.service");
assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC);
/* Initially there's nothing to revert */
assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 0);
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service");
assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0);
/* Revert the override file */
assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 1);
assert_se(changes[0].type == UNIT_FILE_UNLINK);
assert_se(streq(changes[0].path, p));
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d/dropin.conf");
assert_se(mkdir_parents(p, 0755) >= 0);
assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE) >= 0);
/* Revert the dropin file */
assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 2);
assert_se(changes[0].type == UNIT_FILE_UNLINK);
assert_se(streq(changes[0].path, p));
p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d");
assert_se(changes[1].type == UNIT_FILE_UNLINK);
assert_se(streq(changes[1].path, p));
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
}
int main(int argc, char *argv[]) {
char root[] = "/tmp/rootXXXXXX";
const char *p;
@ -656,6 +709,7 @@ int main(int argc, char *argv[]) {
test_template_enable(root);
test_indirect(root);
test_preset_and_list(root);
test_revert(root);
assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);

View file

@ -26,41 +26,38 @@
#include "string-util.h"
#include "strv.h"
static void test_paths(ManagerRunningAs running_as, bool personal) {
static void test_paths(UnitFileScope scope) {
char template[] = "/tmp/test-path-lookup.XXXXXXX";
_cleanup_lookup_paths_free_ LookupPaths lp_without_env = {};
_cleanup_lookup_paths_free_ LookupPaths lp_with_env = {};
char *exists, *not, *systemd_unit_path;
char *systemd_unit_path;
assert_se(mkdtemp(template));
exists = strjoina(template, "/exists");
assert_se(mkdir(exists, 0755) == 0);
not = strjoina(template, "/not");
assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0);
assert_se(!strv_isempty(lp_without_env.unit_path));
assert_se(strv_contains(lp_without_env.unit_path, exists));
assert_se(strv_contains(lp_without_env.unit_path, not));
assert_se(lookup_paths_init(&lp_without_env, scope, 0, NULL) >= 0);
assert_se(!strv_isempty(lp_without_env.search_path));
assert_se(lookup_paths_reduce(&lp_without_env) >= 0);
systemd_unit_path = strjoina(template, "/systemd-unit-path");
assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0);
assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0);
assert_se(strv_length(lp_with_env.unit_path) == 1);
assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path));
assert_se(lookup_paths_init(&lp_with_env, scope, 0, NULL) == 0);
assert_se(strv_length(lp_with_env.search_path) == 1);
assert_se(streq(lp_with_env.search_path[0], systemd_unit_path));
assert_se(lookup_paths_reduce(&lp_with_env) >= 0);
assert_se(strv_length(lp_with_env.search_path) == 0);
assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
static void print_generator_paths(ManagerRunningAs running_as) {
static void print_generator_binary_paths(UnitFileScope scope) {
_cleanup_strv_free_ char **paths;
char **dir;
log_info("Generators dirs (%s):", running_as == MANAGER_SYSTEM ? "system" : "user");
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
paths = generator_paths(running_as);
paths = generator_binary_paths(scope);
STRV_FOREACH(dir, paths)
log_info(" %s", *dir);
}
@ -70,13 +67,12 @@ int main(int argc, char **argv) {
log_parse_environment();
log_open();
test_paths(MANAGER_SYSTEM, false);
test_paths(MANAGER_SYSTEM, true);
test_paths(MANAGER_USER, false);
test_paths(MANAGER_USER, true);
test_paths(UNIT_FILE_SYSTEM);
test_paths(UNIT_FILE_USER);
test_paths(UNIT_FILE_GLOBAL);
print_generator_paths(MANAGER_SYSTEM);
print_generator_paths(MANAGER_USER);
print_generator_binary_paths(UNIT_FILE_SYSTEM);
print_generator_binary_paths(UNIT_FILE_USER);
return EXIT_SUCCESS;
}

View file

@ -30,6 +30,7 @@
#include "string-util.h"
#include "strv.h"
#include "test-helper.h"
#include "tests.h"
#include "unit.h"
#include "util.h"
@ -44,7 +45,7 @@ static int setup_test(Manager **m) {
assert_se(m);
r = manager_new(MANAGER_USER, true, &tmp);
r = manager_new(UNIT_FILE_USER, true, &tmp);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return -EXIT_TEST_SKIP;
@ -243,7 +244,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
}
int main(int argc, char *argv[]) {
test_function_t tests[] = {
static const test_function_t tests[] = {
test_path_exists,
test_path_existsglob,
test_path_changed,
@ -253,12 +254,15 @@ int main(int argc, char *argv[]) {
test_path_makedirectory_directorymode,
NULL,
};
test_function_t *test = NULL;
_cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
const test_function_t *test = NULL;
Manager *m = NULL;
log_parse_environment();
log_open();
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0);
for (test = tests; test && *test; test++) {

View file

@ -1,362 +0,0 @@
/***
This file is part of systemd. See COPYING for details.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* Tests for RB-Tree
*/
#undef NDEBUG
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "c-rbtree.h"
/* verify that all API calls are exported */
static void test_api(void) {
CRBTree t = {};
CRBNode n = C_RBNODE_INIT(n);
assert(!c_rbnode_is_linked(&n));
/* init, is_linked, add, remove, remove_init */
c_rbtree_add(&t, NULL, &t.root, &n);
assert(c_rbnode_is_linked(&n));
c_rbtree_remove_init(&t, &n);
assert(!c_rbnode_is_linked(&n));
c_rbtree_add(&t, NULL, &t.root, &n);
assert(c_rbnode_is_linked(&n));
c_rbtree_remove(&t, &n);
assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */
c_rbnode_init(&n);
assert(!c_rbnode_is_linked(&n));
/* first, last, leftmost, rightmost, next, prev */
assert(!c_rbtree_first(&t));
assert(!c_rbtree_last(&t));
assert(&n == c_rbnode_leftmost(&n));
assert(&n == c_rbnode_rightmost(&n));
assert(!c_rbnode_next(&n));
assert(!c_rbnode_prev(&n));
}
/* copied from c-rbtree.c, relies on internal representation */
static inline _Bool c_rbnode_is_red(CRBNode *n) {
return !((unsigned long)n->__parent_and_color & 1UL);
}
/* copied from c-rbtree.c, relies on internal representation */
static inline _Bool c_rbnode_is_black(CRBNode *n) {
return !!((unsigned long)n->__parent_and_color & 1UL);
}
static size_t validate(CRBTree *t) {
unsigned int i_black, n_black;
CRBNode *n, *p, *o;
size_t count = 0;
assert(t);
assert(!t->root || c_rbnode_is_black(t->root));
/* traverse to left-most child, count black nodes */
i_black = 0;
n = t->root;
while (n && n->left) {
if (c_rbnode_is_black(n))
++i_black;
n = n->left;
}
n_black = i_black;
/*
* Traverse tree and verify correctness:
* 1) A node is either red or black
* 2) The root is black
* 3) All leaves are black
* 4) Every red node must have two black child nodes
* 5) Every path to a leaf contains the same number of black nodes
*
* Note that NULL nodes are considered black, which is why we don't
* check for 3).
*/
o = NULL;
while (n) {
++count;
/* verify natural order */
assert(n > o);
o = n;
/* verify consistency */
assert(!n->right || c_rbnode_parent(n->right) == n);
assert(!n->left || c_rbnode_parent(n->left) == n);
/* verify 2) */
if (!c_rbnode_parent(n))
assert(c_rbnode_is_black(n));
if (c_rbnode_is_red(n)) {
/* verify 4) */
assert(!n->left || c_rbnode_is_black(n->left));
assert(!n->right || c_rbnode_is_black(n->right));
} else {
/* verify 1) */
assert(c_rbnode_is_black(n));
}
/* verify 5) */
if (!n->left && !n->right)
assert(i_black == n_black);
/* get next node */
if (n->right) {
n = n->right;
if (c_rbnode_is_black(n))
++i_black;
while (n->left) {
n = n->left;
if (c_rbnode_is_black(n))
++i_black;
}
} else {
while ((p = c_rbnode_parent(n)) && n == p->right) {
n = p;
if (c_rbnode_is_black(p->right))
--i_black;
}
n = p;
if (p && c_rbnode_is_black(p->left))
--i_black;
}
}
return count;
}
static void insert(CRBTree *t, CRBNode *n) {
CRBNode **i, *p;
assert(t);
assert(n);
assert(!c_rbnode_is_linked(n));
i = &t->root;
p = NULL;
while (*i) {
p = *i;
if (n < *i) {
i = &(*i)->left;
} else {
assert(n > *i);
i = &(*i)->right;
}
}
c_rbtree_add(t, p, i, n);
}
static void shuffle(void **nodes, size_t n_memb) {
unsigned int i, j;
void *t;
for (i = 0; i < n_memb; ++i) {
j = rand() % n_memb;
t = nodes[j];
nodes[j] = nodes[i];
nodes[i] = t;
}
}
/* run some pseudo-random tests on the tree */
static void test_shuffle(void) {
CRBNode *nodes[256];
CRBTree t = {};
unsigned int i, j;
size_t n;
/* allocate and initialize all nodes */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
nodes[i] = malloc(sizeof(*nodes[i]));
assert(nodes[i]);
c_rbnode_init(nodes[i]);
}
/* shuffle nodes and validate *empty* tree */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
n = validate(&t);
assert(n == 0);
/* add all nodes and validate after each insertion */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
insert(&t, nodes[i]);
n = validate(&t);
assert(n == i + 1);
}
/* shuffle nodes again */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
/* remove all nodes (in different order) and validate on each round */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
c_rbtree_remove(&t, nodes[i]);
n = validate(&t);
assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
c_rbnode_init(nodes[i]);
}
/* shuffle nodes and validate *empty* tree again */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
n = validate(&t);
assert(n == 0);
/* add all nodes again */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
insert(&t, nodes[i]);
n = validate(&t);
assert(n == i + 1);
}
/* 4 times, remove half of the nodes and add them again */
for (j = 0; j < 4; ++j) {
/* shuffle nodes again */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
/* remove half of the nodes */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) {
c_rbtree_remove(&t, nodes[i]);
n = validate(&t);
assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
c_rbnode_init(nodes[i]);
}
/* shuffle the removed half */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2);
/* add the removed half again */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) {
insert(&t, nodes[i]);
n = validate(&t);
assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1);
}
}
/* shuffle nodes again */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
/* remove all */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
c_rbtree_remove(&t, nodes[i]);
n = validate(&t);
assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
c_rbnode_init(nodes[i]);
}
/* free nodes again */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i)
free(nodes[i]);
}
typedef struct {
unsigned long key;
CRBNode rb;
} Node;
#define node_from_rb(_rb) ((Node *)((char *)(_rb) - offsetof(Node, rb)))
static int compare(CRBTree *t, void *k, CRBNode *n) {
unsigned long key = (unsigned long)k;
Node *node = node_from_rb(n);
return (key < node->key) ? -1 : (key > node->key) ? 1 : 0;
}
/* run tests against the c_rbtree_find*() helpers */
static void test_map(void) {
CRBNode **slot, *p;
CRBTree t = {};
Node *nodes[2048];
unsigned long i;
/* allocate and initialize all nodes */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
nodes[i] = malloc(sizeof(*nodes[i]));
assert(nodes[i]);
nodes[i]->key = i;
c_rbnode_init(&nodes[i]->rb);
}
/* shuffle nodes */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
/* add all nodes, and verify that each node is linked */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
assert(!c_rbnode_is_linked(&nodes[i]->rb));
assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p);
assert(slot);
c_rbtree_add(&t, p, slot, &nodes[i]->rb);
assert(c_rbnode_is_linked(&nodes[i]->rb));
assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
}
/* shuffle nodes again */
shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
/* remove all nodes (in different order) */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
assert(c_rbnode_is_linked(&nodes[i]->rb));
assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
c_rbtree_remove_init(&t, &nodes[i]->rb);
assert(!c_rbnode_is_linked(&nodes[i]->rb));
assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
}
/* free nodes again */
for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i)
free(nodes[i]);
}
int main(int argc, char **argv) {
unsigned int i;
/* we want stable tests, so use fixed seed */
srand(0xdeadbeef);
test_api();
/*
* The tests are pseudo random; run them multiple times, each run will
* have different orders and thus different results.
*/
for (i = 0; i < 4; ++i) {
test_shuffle();
test_map();
}
return 0;
}

View file

@ -21,9 +21,12 @@
#include "macro.h"
#include "manager.h"
#include "rm-rf.h"
#include "test-helper.h"
#include "tests.h"
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
Manager *m = NULL;
Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
Service *ser;
@ -31,9 +34,11 @@ int main(int argc, char *argv[]) {
FDSet *fdset = NULL;
int r;
assert_se(runtime_dir = setup_fake_runtime_dir());
/* prepare the test */
assert_se(set_unit_path(TEST_DIR) >= 0);
r = manager_new(MANAGER_USER, true, &m);
r = manager_new(UNIT_FILE_USER, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return EXIT_TEST_SKIP;

View file

@ -35,10 +35,12 @@
#include "install.h"
#include "load-fragment.h"
#include "macro.h"
#include "rm-rf.h"
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
#include "test-helper.h"
#include "tests.h"
#include "user-util.h"
#include "util.h"
@ -113,7 +115,7 @@ static void test_config_parse_exec(void) {
Manager *m = NULL;
Unit *u = NULL;
r = manager_new(MANAGER_USER, true, &m);
r = manager_new(UNIT_FILE_USER, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return;
@ -840,11 +842,14 @@ static void test_config_parse_pass_environ(void) {
}
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
int r;
log_parse_environment();
log_open();
assert_se(runtime_dir = setup_fake_runtime_dir());
r = test_unit_file_get_set();
test_config_parse_exec();
test_config_parse_capability_set();

View file

@ -209,7 +209,7 @@ static int test_unit_printf(void) {
assert_se(get_home_dir(&home) >= 0);
assert_se(get_shell(&shell) >= 0);
r = manager_new(MANAGER_USER, true, &m);
r = manager_new(UNIT_FILE_USER, true, &m);
if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;