summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CODING_STYLE1
-rw-r--r--Makefile.am19
-rw-r--r--NEWS3
-rw-r--r--README1
-rw-r--r--TODO27
-rw-r--r--coccinelle/strjoina.cocci6
-rw-r--r--hwdb/60-evdev.hwdb7
-rw-r--r--hwdb/60-keyboard.hwdb2
-rw-r--r--hwdb/70-mouse.hwdb32
-rw-r--r--man/journalctl.xml4
-rw-r--r--man/machinectl.xml50
-rw-r--r--man/systemctl.xml40
-rw-r--r--man/systemd-nspawn.xml15
-rw-r--r--man/systemd-run.xml8
-rw-r--r--man/systemd-tmpfiles.xml10
-rw-r--r--man/systemd.automount.xml8
-rw-r--r--man/systemd.exec.xml9
-rw-r--r--man/systemd.mount.xml31
-rw-r--r--man/systemd.netdev.xml11
-rw-r--r--man/systemd.network.xml22
-rw-r--r--man/systemd.path.xml16
-rw-r--r--man/systemd.service.xml19
-rw-r--r--man/systemd.slice.xml12
-rw-r--r--man/systemd.socket.xml16
-rw-r--r--man/systemd.swap.xml10
-rw-r--r--man/systemd.target.xml13
-rw-r--r--man/systemd.timer.xml24
-rw-r--r--man/systemd.unit.xml10
-rw-r--r--man/tmpfiles.d.xml81
-rw-r--r--rules/99-systemd.rules.in6
-rw-r--r--shell-completion/zsh/_coredumpctl2
-rw-r--r--shell-completion/zsh/_networkctl35
-rw-r--r--src/analyze/analyze-verify.c8
-rw-r--r--src/analyze/analyze-verify.h2
-rw-r--r--src/analyze/analyze.c2
-rw-r--r--src/basic/c-rbtree.c674
-rw-r--r--src/basic/c-rbtree.h297
-rw-r--r--src/basic/def.h2
-rw-r--r--src/basic/missing.h39
-rw-r--r--src/basic/path-util.c8
-rw-r--r--src/basic/path-util.h17
-rw-r--r--src/basic/rm-rf.h9
-rw-r--r--src/basic/signal-util.c2
-rw-r--r--src/basic/signal-util.h4
-rw-r--r--src/basic/strv.c36
-rw-r--r--src/basic/strv.h1
-rw-r--r--src/basic/terminal-util.c19
-rw-r--r--src/basic/user-util.c1
-rw-r--r--src/basic/util.c39
-rw-r--r--src/basic/util.h2
-rw-r--r--src/core/automount.c2
-rw-r--r--src/core/busname.c4
-rw-r--r--src/core/cgroup.c4
-rw-r--r--src/core/dbus-execute.c8
-rw-r--r--src/core/dbus-kill.c4
-rw-r--r--src/core/dbus-manager.c187
-rw-r--r--src/core/dbus-timer.c2
-rw-r--r--src/core/dbus-unit.c5
-rw-r--r--src/core/dbus.c16
-rw-r--r--src/core/device.c2
-rw-r--r--src/core/failure-action.c16
-rw-r--r--src/core/job.c4
-rw-r--r--src/core/load-dropin.c15
-rw-r--r--src/core/load-dropin.h2
-rw-r--r--src/core/load-fragment.c31
-rw-r--r--src/core/machine-id-setup.c8
-rw-r--r--src/core/main.c50
-rw-r--r--src/core/manager.c292
-rw-r--r--src/core/manager.h17
-rw-r--r--src/core/mount-setup.c1
-rw-r--r--src/core/mount.c17
-rw-r--r--src/core/org.freedesktop.systemd1.conf4
-rw-r--r--src/core/path.c10
-rw-r--r--src/core/scope.c31
-rw-r--r--src/core/service.c39
-rw-r--r--src/core/shutdown.c9
-rw-r--r--src/core/slice.c1
-rw-r--r--src/core/socket.c2
-rw-r--r--src/core/swap.c4
-rw-r--r--src/core/timer.c6
-rw-r--r--src/core/transaction.c4
-rw-r--r--src/core/unit-printf.c11
-rw-r--r--src/core/unit.c237
-rw-r--r--src/core/unit.h3
-rw-r--r--src/coredump/coredump.c86
-rw-r--r--src/import/curl-util.c4
-rw-r--r--src/import/pull-job.h9
-rw-r--r--src/journal/fsprg.c2
-rw-r--r--src/journal/journald-server.c48
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c2
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c3
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c14
-rw-r--r--src/libsystemd/sd-event/sd-event.c7
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c43
-rw-r--r--src/libsystemd/sd-resolve/sd-resolve.c5
-rw-r--r--src/locale/localed.c76
-rw-r--r--src/login/logind-session-dbus.c3
-rw-r--r--src/login/logind-session.c4
-rw-r--r--src/login/logind-user-dbus.c3
-rw-r--r--src/machine/machine-dbus.c5
-rw-r--r--src/machine/machinectl.c53
-rw-r--r--src/machine/machined-dbus.c88
-rw-r--r--src/network/networkd-address-pool.c6
-rw-r--r--src/network/networkd-dhcp4.c4
-rw-r--r--src/network/networkd-link.c85
-rw-r--r--src/network/networkd-lldp-tx.c6
-rw-r--r--src/network/networkd-netdev-bridge.c17
-rw-r--r--src/network/networkd-netdev-bridge.h2
-rw-r--r--src/network/networkd-netdev-gperf.gperf1
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c14
-rw-r--r--src/network/networkd-network.h3
-rw-r--r--src/network/networkd-route.c15
-rw-r--r--src/nspawn/nspawn.c118
-rw-r--r--src/resolve/resolved-bus.c5
-rw-r--r--src/resolve/resolved-dns-dnssec.c2
-rw-r--r--src/resolve/resolved-dns-transaction.c4
-rw-r--r--src/resolve/test-dnssec.c273
-rw-r--r--src/run/run.c15
-rw-r--r--src/shared/bus-util.c19
-rw-r--r--src/shared/conf-parser.c2
-rw-r--r--src/shared/firewall-util.c12
-rw-r--r--src/shared/install.c973
-rw-r--r--src/shared/install.h126
-rw-r--r--src/shared/machine-image.c12
-rw-r--r--src/shared/machine-image.h26
-rw-r--r--src/shared/path-lookup.c798
-rw-r--r--src/shared/path-lookup.h78
-rw-r--r--src/shared/sleep-config.c4
-rw-r--r--src/shared/tests.c33
-rw-r--r--src/shared/tests.h22
-rw-r--r--src/systemctl/systemctl.c323
-rw-r--r--src/systemd/sd-lldp.h74
-rw-r--r--src/sysv-generator/sysv-generator.c55
-rw-r--r--src/test/test-cgroup-mask.c8
-rw-r--r--src/test/test-engine.c7
-rw-r--r--src/test/test-execute.c8
-rw-r--r--src/test/test-install-root.c58
-rw-r--r--src/test/test-install.c42
-rw-r--r--src/test/test-namespace.c9
-rw-r--r--src/test/test-nss.c6
-rw-r--r--src/test/test-path-lookup.c40
-rw-r--r--src/test/test-path-util.c12
-rw-r--r--src/test/test-path.c10
-rw-r--r--src/test/test-rbtree.c362
-rw-r--r--src/test/test-sched-prio.c7
-rw-r--r--src/test/test-strv.c10
-rw-r--r--src/test/test-udev.c44
-rw-r--r--src/test/test-unit-file.c7
-rw-r--r--src/test/test-unit-name.c2
-rw-r--r--src/tmpfiles/tmpfiles.c88
-rw-r--r--src/udev/udevadm-monitor.c2
-rw-r--r--src/udev/udevd.c7
-rwxr-xr-xtest/TEST-07-ISSUE-1981/test.sh3
-rw-r--r--test/test-functions7
157 files changed, 3705 insertions, 3380 deletions
diff --git a/.gitignore b/.gitignore
index 403c16c339..02ba86ef6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -249,7 +249,6 @@
/test-pty
/test-qcow2
/test-ratelimit
-/test-rbtree
/test-replace-var
/test-resolve
/test-resolve-tables
diff --git a/CODING_STYLE b/CODING_STYLE
index e5ba396368..c2b2e56d5d 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -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).
diff --git a/Makefile.am b/Makefile.am
index e97d5bd78f..f2ef83b0c7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
@@ -3028,7 +3021,9 @@ systemd_nspawn_SOURCES = \
src/core/mount-setup.c \
src/core/mount-setup.h \
src/core/loopback-setup.c \
- src/core/loopback-setup.h
+ src/core/loopback-setup.h \
+ src/core/machine-id-setup.c \
+ src/core/machine-id-setup.h
nodist_systemd_nspawn_SOURCES = \
src/nspawn/nspawn-gperf.c
@@ -4728,7 +4723,7 @@ systemd_localed_SOURCES = \
systemd_localed_LDADD = \
libshared.la \
- $(XKBCOMMON_LIBS)
+ -ldl
systemd_localed_CFLAGS = \
$(AM_CFLAGS) \
diff --git a/NEWS b/NEWS
index 3924264e6f..f697599a8f 100644
--- a/NEWS
+++ b/NEWS
@@ -442,6 +442,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.
diff --git a/README b/README
index 0118c102f6..ca8993cb12 100644
--- a/README
+++ b/README
@@ -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)
diff --git a/TODO b/TODO
index b2840ba4ab..4d8161cadf 100644
--- a/TODO
+++ b/TODO
@@ -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
+
+* 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.
-* machinectl remove --hidden + machinectl remove --all
+* 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.
@@ -564,8 +571,6 @@ Features:
- to allow "linking" of nspawn containers, extend --network-bridge= so
that it can dynamically create bridge interfaces that are refcounted
by the containers on them. For each group of containers to link together
- - refuses to boot containers without /etc/machine-id (OK?), and with empty
- /etc/machine-id (not OK).
- nspawn -x should support ephemeral instances of gpt images
- emulate /dev/kmsg using CUSE and turn off the syslog syscall
with seccomp. That should provide us with a useful log buffer that
diff --git a/coccinelle/strjoina.cocci b/coccinelle/strjoina.cocci
new file mode 100644
index 0000000000..a6236eb0f9
--- /dev/null
+++ b/coccinelle/strjoina.cocci
@@ -0,0 +1,6 @@
+@@
+expression n, m;
+expression list s;
+@@
+- n = strjoina(m, s, NULL);
++ n = strjoina(m, s);
diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb
index 4f04539e12..547db3a2ca 100644
--- a/hwdb/60-evdev.hwdb
+++ b/hwdb/60-evdev.hwdb
@@ -127,6 +127,13 @@ evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLati
EVDEV_ABS_35=76:1815:22
EVDEV_ABS_36=131:1330:30
+# Dell XPS15 9550
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPS159550*
+ EVDEV_ABS_00=::41
+ EVDEV_ABS_01=::43
+ EVDEV_ABS_35=::41
+ EVDEV_ABS_36=::43
+
#########################################
# Google
#########################################
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 46013d3449..ffd06f040c 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -502,6 +502,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:*
# HP ProBook 440 G3
evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*440*G3*
+# HP ProBook 640 G2
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*640*G2*
KEYBOARD_KEY_85=unknown # lid close; also reported via special evdev
KEYBOARD_KEY_f8=unknown # rf kill; also reported via special evdev
diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb
index 54ace7cbc1..bea0464a11 100644
--- a/hwdb/70-mouse.hwdb
+++ b/hwdb/70-mouse.hwdb
@@ -132,6 +132,14 @@ mouse:usb:v046dpc063:name:DELL DELL USB Laser Mouse:
MOUSE_DPI=1000@125
##########################################
+# Dynex
+#########################################
+
+# Dynex Wired Optical Mouse (DX-WMSE2)
+mouse:usb:v0461p4d46:name:USB Optical Mouse:
+ MOUSE_DPI=1000@125
+
+##########################################
# Fujitsu Siemens
##########################################
@@ -420,6 +428,14 @@ mouse:usb:v22d4p1308:name:Laview Technology Mionix Avior 7000:
MOUSE_WHEEL_CLICK_ANGLE=15
##########################################
+# MODECOM
+##########################################
+
+# MODECOM MC-WM4 Wireless Optical Mouse
+mouse:usb:v0e8fp00a7:name:DaKai 2.4G RX:
+ MOUSE_DPI=*800@126 1600@126
+
+##########################################
# Oklick
##########################################
@@ -443,3 +459,19 @@ mouse:usb:v1532p0042:name:Razer Razer Abyssus:
mouse:usb:v1e7dp2c2e:name:ROCCAT ROCCAT Lua:
MOUSE_DPI=250@125 500@125 1000@125 1250@125 1500@125 1750@125 2000@125 250@250 500@250 1000@250 1250@250 1500@250 1750@250 2000@250 250@500 500@500 1000@500 1250@500 1500@500 1750@500 2000@500 250@1000 500@1000 *1000@1000 1250@1000 1500@1000 1750@1000 2000@1000
MOUSE_WHEEL_CLICK_ANGLE=15
+
+##########################################
+# Sharkoon
+##########################################
+
+# Sharkoon Shark Force Gaming Mouse
+mouse:usb:v093ap2521:name:USB OPTICAL MOUSE:
+ MOUSE_DPI=*1000@125 1600@125 600@125
+
+##########################################
+# SteelSeries
+##########################################
+
+# SteelSeries Sensei Raw
+mouse:usb:v1038p1369:name:SteelSeries Sensei Raw Gaming Mouse:
+ MOUSE_DPI=1000@1022
diff --git a/man/journalctl.xml b/man/journalctl.xml
index b281f26b45..7a634879cc 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -673,9 +673,9 @@
space they use falls below the specified size (specified with
the usual <literal>K</literal>, <literal>M</literal>,
<literal>G</literal> and <literal>T</literal> suffixes), or all
- journal files contain no data older than the specified
+ archived journal files contain no data older than the specified
timespan (specified with the usual <literal>s</literal>,
- <literal>min</literal>, <literal>h</literal>,
+ <literal>m</literal>, <literal>h</literal>,
<literal>days</literal>, <literal>months</literal>,
<literal>weeks</literal> and <literal>years</literal> suffixes),
or no more than the specified number of separate journal files
diff --git a/man/machinectl.xml b/man/machinectl.xml
index cee4bb72ce..43a3b98840 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -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>
@@ -193,16 +195,14 @@
</varlistentry>
<varlistentry>
- <term><option>--setenv=</option></term>
-
- <listitem><para>When used with the <command>shell</command>
- command, sets an environment variable to pass to the executed
- shell. Takes a pair of environment variable name and value,
- separated by <literal>=</literal> as argument. This switch
- may be used multiple times to set multiple environment
- variables. Note that this switch is not supported for the
- <command>login</command> command (see
- below).</para></listitem>
+ <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+ <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+
+ <listitem><para>When used with the <command>shell</command> command, sets an environment
+ variable to pass to the executed shell. Takes an environment variable name and value,
+ separated by <literal>=</literal>. This switch may be used multiple times to set multiple
+ environment variables. Note that this switch is not supported for the
+ <command>login</command> command (see below).</para></listitem>
</varlistentry>
<varlistentry>
@@ -217,9 +217,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 +601,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 +665,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>
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 089fb0f5c3..5f624243f7 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -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>
@@ -1235,6 +1245,28 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</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>
<term><command>add-requires <replaceable>TARGET</replaceable>
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 7e87865ba8..6732b9d7be 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -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>
@@ -355,7 +355,9 @@
<listitem><para>Set the specified UUID for the container. The
init system will initialize
<filename>/etc/machine-id</filename> from this if this file is
- not set yet. </para></listitem>
+ not set yet. Note that this option takes effect only if
+ <filename>/etc/machine-id</filename> in the container is
+ unpopulated.</para></listitem>
</varlistentry>
<varlistentry>
@@ -735,7 +737,8 @@
</varlistentry>
<varlistentry>
- <term><option>--setenv=</option></term>
+ <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+ <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
<listitem><para>Specifies an environment variable assignment
to pass to the init process in the container, in the format
diff --git a/man/systemd-run.xml b/man/systemd-run.xml
index 0d58356e00..9c1a29218e 100644
--- a/man/systemd-run.xml
+++ b/man/systemd-run.xml
@@ -226,11 +226,11 @@
</varlistentry>
<varlistentry>
- <term><option>--setenv=</option></term>
+ <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+ <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
- <listitem><para>Runs the service process with the specified
- environment variables set. Also see
- <varname>Environment=</varname> in
+ <listitem><para>Runs the service process with the specified environment variable set.
+ Also see <varname>Environment=</varname> in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
index 447a7eaa17..c1aab51551 100644
--- a/man/systemd-tmpfiles.xml
+++ b/man/systemd-tmpfiles.xml
@@ -75,11 +75,11 @@
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
- <para>If invoked with no arguments, it applies all directives from
- all configuration files. If one or more absolute filenames are passed on
- the command line, only the directives in these files are applied.
- If only the basename of a configuration file is specified, all
- configuration directories as specified in
+ <para>If invoked with no arguments, it applies all directives from all configuration
+ files. If one or more absolute filenames are passed on the command line, only the
+ directives in these files are applied. If <literal>-</literal> is specified instead
+ of a filename, directives are read from standard input. If only the basename of a
+ configuration file is specified, all configuration directories as specified in
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
are searched for a matching file.</para>
</refsect1>
diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml
index 1b0ae832da..93bae2a6dc 100644
--- a/man/systemd.automount.xml
+++ b/man/systemd.automount.xml
@@ -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>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 3e1a2cb224..4ed62dbada 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -859,9 +859,12 @@
reading only, writing will be refused even if the usual file
access controls would permit this. Directories listed in
<varname>InaccessibleDirectories=</varname> will be made
- inaccessible for processes inside the namespace. Note that
- restricting access with these options does not extend to
- submounts of a directory that are created later on. These
+ inaccessible for processes inside the namespace, and may not
+ countain any other mountpoints, including those specified by
+ <varname>ReadWriteDirectories=</varname> or
+ <varname>ReadOnlyDirectories=</varname>.
+ Note that restricting access with these options does not extend
+ to submounts of a directory that are created later on. These
options may be specified more than once, in which case all
directories listed will have limited access from within the
namespace. If the empty string is assigned to this option, the
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index 4a8d265fed..f116782b40 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -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
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index c5fb2fa7fb..48c283c8df 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -310,6 +310,17 @@
of the Listening and Learning states before the Forwarding state is entered.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>MulticastQuerier=</varname></term>
+ <listitem>
+ <para>A boolean. This setting controls the IFLA_BR_MCAST_QUERIER option in the kernel.
+ If enabled, the kernel will send general ICMP queries from a zero source address.
+ This feature should allow faster convergence on startup, but it causes some
+ multicast-aware switches to misbehave and disrupt forwarding of multicast packets.
+ When unset, the kernel's default setting applies.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index c9ef041004..8ae384185d 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -202,6 +202,8 @@
<para>The maximum transmission unit in bytes to set for the
device. The usual suffixes K, M, G, are supported and are
understood to the base of 1024.</para>
+ <para>Note that if IPv6 is enabled on the interface, and the MTU is chosen
+ below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -210,6 +212,15 @@
<para>Identity Association Identifier for the interface, a 32-bit unsigned integer.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <listitem>
+ <para>Note that an interface without any static IPv6 addresses configured, and neither
+ DHCPv6 nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be
+ automatically disabled for that interface by writing "1" to
+ <filename>/proc/sys/net/ipv6/conf/<replaceable>ifname</replaceable>/disable_ipv6.</filename>
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -549,6 +560,15 @@
</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>ProxyARP=</varname></term>
+ <listitem><para>A boolean. Configures proxy ARP. Proxy ARP is the technique in which one host,
+ usually a router, answers ARP requests intended for another machine. By "faking" its identity,
+ the router accepts responsibility for routing packets to the "real" destination. (see <ulink
+ url="https://tools.ietf.org/html/rfc1027">RFC 1027</ulink>.
+ Defaults to unset.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Bridge=</varname></term>
<listitem>
<para>The name of the bridge to add the link to.</para>
@@ -844,7 +864,7 @@
global DUID that may be specified in <citerefentry><refentrytitle>networkd.conf
</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
- <para>The configured DHCP DUID should conform to the specification in
+ <para>The configured DHCP DUID should conform to the specification in
<ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
<ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>.</para>
diff --git a/man/systemd.path.xml b/man/systemd.path.xml
index 1bd65ce86d..7200c8fe27 100644
--- a/man/systemd.path.xml
+++ b/man/systemd.path.xml
@@ -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>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index e55534700a..6641dfed4f 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -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
diff --git a/man/systemd.slice.xml b/man/systemd.slice.xml
index 5c87bf0260..16247628af 100644
--- a/man/systemd.slice.xml
+++ b/man/systemd.slice.xml
@@ -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>
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 43841c2399..2d6339680b 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -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
diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml
index 69d4be4769..6fc4c7bf13 100644
--- a/man/systemd.swap.xml
+++ b/man/systemd.swap.xml
@@ -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
diff --git a/man/systemd.target.xml b/man/systemd.target.xml
index bd4ab3903e..ab910d75dd 100644
--- a/man/systemd.target.xml
+++ b/man/systemd.target.xml
@@ -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>
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 29e235e2dc..22c83f790f 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -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>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index f5022b03cc..7993301167 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -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>
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 3b6b1e3f11..957475d2bd 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -157,13 +157,23 @@
<varlistentry>
<term><varname>d</varname></term>
- <listitem><para>Create a directory if it does not exist yet.
- </para></listitem>
+ <listitem><para>Create a directory. The mode and ownership will be adjusted if
+ specified and the directory already exists. Contents of this directory are subject
+ to time based cleanup if the time argument is specified.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>D</varname></term>
- <listitem><para>Create or empty a directory.</para></listitem>
+ <listitem><para>Similar to <varname>d</varname>, but in addition the contents
+ of the directory will be removed when <option>--remove</option> is used.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>e</varname></term>
+ <listitem><para>Similar to <varname>d</varname>, but the directory will not be
+ created if it does not exist. Lines of this type accept shell-style globs in
+ place of normal path names.</para></listitem>
</varlistentry>
<varlistentry>
@@ -577,7 +587,7 @@
unconditionally.</para>
<para>The age field only applies to lines starting with
- <varname>d</varname>, <varname>D</varname>,
+ <varname>d</varname>, <varname>D</varname>, <varname>e</varname>,
<varname>v</varname>, <varname>q</varname>,
<varname>Q</varname>, <varname>C</varname>, <varname>x</varname>
and <varname>X</varname>. If omitted or set to
@@ -612,22 +622,63 @@
</refsect1>
<refsect1>
- <title>Example</title>
+ <title>Examples</title>
<example>
- <title>/etc/tmpfiles.d/screen.conf example</title>
- <para><command>screen</command> needs two directories created at
- boot with specific modes and ownership.</para>
+ <title>Create directories with specific mode and ownership</title>
+ <para>
+ <citerefentry><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ needs two directories created at boot with specific modes and ownership:</para>
+
+ <programlisting># /usr/lib/tmpfiles.d/screen.conf
+d /run/screens 1777 root screen 10d
+d /run/uscreens 0755 root screen 10d12h
+</programlisting>
+
+ <para>Contents of <filename>/run/screens</filename> and /run/uscreens will
+ cleaned up after 10 and 10½ days, respectively.</para>
+ </example>
- <programlisting>d /run/screens 1777 root root 10d
-d /run/uscreens 0755 root root 10d12h
-t /run/screen - - - - user.name="John Smith" security.SMACK64=screen</programlisting>
+ <example>
+ <title>Create a directory with a SMACK attribute</title>
+ <programlisting>D /run/cups - - - -
+t /run/cups - - - - security.SMACK64=printing user.attr-with-spaces="foo bar"
+ </programlisting>
+
+ <para>The direcory will be owned by root and have default mode. It's contents are
+ not subject to time based cleanup, but will be obliterated when
+ <command>systemd-tmpfiles --remove</command> runs.</para>
</example>
+
<example>
- <title>/etc/tmpfiles.d/abrt.conf example</title>
- <para><command>abrt</command> needs a directory created at boot with specific mode and ownership and its content should be preserved.</para>
+ <title>Create a directory and prevent its contents from cleanup</title>
+ <para>
+ <citerefentry><refentrytitle>abrt</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ needs a directory created at boot with specific mode and ownership and its content
+ should be preserved from the automatic cleanup applied to the contents of
+ <filename>/var/tmp</filename>:</para>
+
+ <programlisting># /usr/lib/tmpfiles.d/tmp.conf
+d /var/tmp 1777 root root 30d
+</programlisting>
+
+ <programlisting># /usr/lib/tmpfiles.d/abrt.conf
+d /var/tmp/abrt 0755 abrt abrt -
+</programlisting>
+ </example>
- <programlisting>d /var/tmp/abrt 0755 abrt abrt
-x /var/tmp/abrt/*</programlisting>
+ <example>
+ <title>Apply clean up during boot and based on time</title>
+
+ <programlisting># /usr/lib/tmpfiles.d/dnf.conf
+r! /var/cache/dnf/*/*/download_lock.pid
+r! /var/cache/dnf/*/*/metadata_lock.pid
+r! /var/lib/dnf/rpmdb_lock.pid
+e /var/chache/dnf/ - - - 30d
+</programlisting>
+
+ <para>The lock files will be removed during boot. Any files and directories in
+ <filename>/var/chache/dnf/</filename> will be removed after they have not been
+ accessed in 30 days.</para>
</example>
</refsect1>
diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in
index 5c2cda51ec..fb4517606d 100644
--- a/rules/99-systemd.rules.in
+++ b/rules/99-systemd.rules.in
@@ -11,7 +11,7 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270
KERNEL=="vport*", TAG+="systemd"
SUBSYSTEM=="block", TAG+="systemd"
-SUBSYSTEM=="block", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
# Ignore encrypted devices with no identified superblock on it, since
# we are probably still calling mke2fs or mkswap on it.
@@ -24,8 +24,8 @@ SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="
# Ignore loop devices that don't have any file attached
SUBSYSTEM=="block", KERNEL=="loop[0-9]*", ENV{DEVTYPE}=="disk", TEST!="loop/backing_file", ENV{SYSTEMD_READY}="0"
-# Ignore nbd devices in the "add" event, with "change" the nbd is ready
-ACTION=="add", SUBSYSTEM=="block", KERNEL=="nbd*", ENV{SYSTEMD_READY}="0"
+# Ignore nbd devices until the PID file exists (which signals a connected device)
+SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTEMD_READY}="0"
# We need a hardware independent way to identify network devices. We
# use the /sys/subsystem/ path for this. Kernel "bus" and "class" names
diff --git a/shell-completion/zsh/_coredumpctl b/shell-completion/zsh/_coredumpctl
index 833c7e2bb1..e4c04a697f 100644
--- a/shell-completion/zsh/_coredumpctl
+++ b/shell-completion/zsh/_coredumpctl
@@ -16,7 +16,7 @@ _coredumpctl_command(){
cmd="${${_coredumpctl_cmds[(r)$words[1]:*]%%:*}}"
if (( $#cmd )); then
# user can set zstyle ':completion:*:*:coredumpctl:*' sort no for coredumps to be ordered by date, otherwise they get ordered by pid
- _dumps=( "${(foa)$(coredumpctl list | awk 'BEGIN{OFS=":"} /^\s/ {sub(/[[ \t]+/, ""); print $5,$0}' 2>/dev/null)}" )
+ _dumps=( "${(foa)$(coredumpctl list --no-legend | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $5,$0}' 2>/dev/null)}" )
if [[ -n "$_dumps" ]]; then
_describe -t pids 'coredumps' _dumps
else
diff --git a/shell-completion/zsh/_networkctl b/shell-completion/zsh/_networkctl
new file mode 100644
index 0000000000..61f173b78e
--- /dev/null
+++ b/shell-completion/zsh/_networkctl
@@ -0,0 +1,35 @@
+#compdef networkctl
+
+_networkctl_command(){
+ local -a _networkctl_cmds
+ _networkctl_cmds=(
+ 'list:List existing links'
+ 'status:Show information about the specified links'
+ 'lldp:Show Link Layer Discovery Protocol status'
+ )
+ if (( CURRENT == 1 )); then
+ _describe -t commands 'networkctl command' _networkctl_cmds
+ else
+ local curcontext="$curcontext"
+ local -a _links
+ cmd="${${_networkctl_cmds[(r)$words[1]:*]%%:*}}"
+ if [ $cmd = "status" ]; then
+ _links=( "${(foa)$(networkctl list --no-legend | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $2,$0}' 2>/dev/null)}" )
+ if [[ -n "$_links" ]]; then
+ _describe -t links 'links' _links
+ else
+ _message "no links"
+ fi
+ else
+ _message "no more options"
+ fi
+ fi
+}
+
+_arguments \
+ {-a,--all}'[Show all links with status]' \
+ '--no-pager[Do not pipe output into a pager]' \
+ '--no-legend[Do not print the column headers]' \
+ {-h,--help}'[Show this help]' \
+ '--version[Show package version]' \
+ '*::networkctl commands:_networkctl_command'
diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c
index b83f559e7d..5fd3ee49eb 100644
--- a/src/analyze/analyze-verify.c
+++ b/src/analyze/analyze-verify.c
@@ -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");
diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h
index 27c253a562..d8204dc69c 100644
--- a/src/analyze/analyze-verify.h
+++ b/src/analyze/analyze-verify.h
@@ -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);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 42754a2741..5e03c0c5e0 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -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;
diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c
deleted file mode 100644
index cf5a7242df..0000000000
--- a/src/basic/c-rbtree.c
+++ /dev/null
@@ -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);
-}
diff --git a/src/basic/c-rbtree.h b/src/basic/c-rbtree.h
deleted file mode 100644
index 20c5515ca1..0000000000
--- a/src/basic/c-rbtree.h
+++ /dev/null
@@ -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
diff --git a/src/basic/def.h b/src/basic/def.h
index 963343eb7d..1a7a0f4928 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -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" \
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 66cd5921ad..6616f0b720 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -746,7 +746,40 @@ struct btrfs_ioctl_quota_ctl_args {
#define IFLA_BR_AGEING_TIME 4
#define IFLA_BR_STP_STATE 5
#define IFLA_BR_PRIORITY 6
-#define __IFLA_BR_MAX 7
+#define IFLA_BR_VLAN_FILTERING 7
+#define IFLA_BR_VLAN_PROTOCOL 8
+#define IFLA_BR_GROUP_FWD_MASK 9
+#define IFLA_BR_ROOT_ID 10
+#define IFLA_BR_BRIDGE_ID 11
+#define IFLA_BR_ROOT_PORT 12
+#define IFLA_BR_ROOT_PATH_COST 13
+#define IFLA_BR_TOPOLOGY_CHANGE 14
+#define IFLA_BR_TOPOLOGY_CHANGE_DETECTED 15
+#define IFLA_BR_HELLO_TIMER 16
+#define IFLA_BR_TCN_TIMER 17
+#define IFLA_BR_TOPOLOGY_CHANGE_TIMER 18
+#define IFLA_BR_GC_TIMER 19
+#define IFLA_BR_GROUP_ADDR 20
+#define IFLA_BR_FDB_FLUSH 21
+#define IFLA_BR_MCAST_ROUTER 22
+#define IFLA_BR_MCAST_SNOOPING 23
+#define IFLA_BR_MCAST_QUERY_USE_IFADDR 24
+#define IFLA_BR_MCAST_QUERIER 25
+#define IFLA_BR_MCAST_HASH_ELASTICITY 26
+#define IFLA_BR_MCAST_HASH_MAX 27
+#define IFLA_BR_MCAST_LAST_MEMBER_CNT 28
+#define IFLA_BR_MCAST_STARTUP_QUERY_CNT 29
+#define IFLA_BR_MCAST_LAST_MEMBER_INTVL 30
+#define IFLA_BR_MCAST_MEMBERSHIP_INTVL 31
+#define IFLA_BR_MCAST_QUERIER_INTVL 32
+#define IFLA_BR_MCAST_QUERY_INTVL 33
+#define IFLA_BR_MCAST_QUERY_RESPONSE_INTVL 34
+#define IFLA_BR_MCAST_STARTUP_QUERY_INTVL 35
+#define IFLA_BR_NF_CALL_IPTABLES 36
+#define IFLA_BR_NF_CALL_IP6TABLES 37
+#define IFLA_BR_NF_CALL_ARPTABLES 38
+#define IFLA_BR_VLAN_DEFAULT_PVID 39
+#define __IFLA_BR_MAX 40
#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
#endif
@@ -795,6 +828,10 @@ struct btrfs_ioctl_quota_ctl_args {
#define IPV6_UNICAST_IF 76
#endif
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
+
#ifndef IFF_MULTI_QUEUE
#define IFF_MULTI_QUEUE 0x100
#endif
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 822c09bfba..044a12889d 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -569,10 +569,10 @@ static int binary_is_good(const char *binary) {
if (r < 0)
return r;
- return !path_equal(d, "true") &&
- !path_equal(d, "/bin/true") &&
- !path_equal(d, "/usr/bin/true") &&
- !path_equal(d, "/dev/null");
+ return !PATH_IN_SET(d, "true"
+ "/bin/true",
+ "/usr/bin/true",
+ "/dev/null");
}
int fsck_exists(const char *fstype) {
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 2c2f87a9f2..34d5cd1570 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -48,6 +48,23 @@ bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b);
char* path_join(const char *root, const char *path, const char *rest);
+static inline bool path_equal_ptr(const char *a, const char *b) {
+ return !!a == !!b && (!a || path_equal(a, b));
+}
+
+/* Note: the search terminates on the first NULL item. */
+#define PATH_IN_SET(p, ...) \
+ ({ \
+ char **s; \
+ bool _found = false; \
+ STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \
+ if (path_equal(p, *s)) { \
+ _found = true; \
+ break; \
+ } \
+ _found; \
+ })
+
int path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix);
diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h
index 6d03268919..40b5b527d5 100644
--- a/src/basic/rm-rf.h
+++ b/src/basic/rm-rf.h
@@ -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);
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index e3047b209b..280b5c3251 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -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;
diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h
index a7322ff26a..dfd6eb564d 100644
--- a/src/basic/signal-util.h
+++ b/src/basic/signal-util.h
@@ -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;
+}
diff --git a/src/basic/strv.c b/src/basic/strv.c
index 8282298dca..97a96e5762 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -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;
diff --git a/src/basic/strv.h b/src/basic/strv.h
index 7bfa54408d..f61bbb5386 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -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);
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index 0a9d2bbdef..9521b79daa 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -1135,14 +1135,19 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
}
bool colors_enabled(void) {
- const char *colors;
+ static int enabled = -1;
- colors = getenv("SYSTEMD_COLORS");
- if (!colors) {
- if (streq_ptr(getenv("TERM"), "dumb"))
- return false;
- return on_tty();
+ if (_unlikely_(enabled < 0)) {
+ const char *colors;
+
+ colors = getenv("SYSTEMD_COLORS");
+ if (colors)
+ enabled = parse_boolean(colors) != 0;
+ else if (streq_ptr(getenv("TERM"), "dumb"))
+ enabled = false;
+ else
+ enabled = on_tty();
}
- return parse_boolean(colors) != 0;
+ return enabled;
}
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 19155bce53..f65ca3edaa 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -30,6 +30,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "missing.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "formats-util.h"
diff --git a/src/basic/util.c b/src/basic/util.c
index ea1bed7ceb..b70c50047f 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -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"
@@ -419,13 +420,17 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
_exit(EXIT_FAILURE);
}
- if (!stdout_is_tty)
- dup2(fd, STDOUT_FILENO);
+ if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
+ log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
- if (!stderr_is_tty)
- dup2(fd, STDERR_FILENO);
+ if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
+ log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
- if (fd > 2)
+ if (fd > STDERR_FILENO)
close(fd);
}
@@ -773,15 +778,25 @@ 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 (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");
+ }
- if (param) {
- r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
+ return 0;
+ }
+
+ RUN_WITH_UMASK(0022) {
+ r = write_string_file("/run/systemd/reboot-param", 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);
+ return log_warning_errno(r, "Failed to write reboot parameter file: %m");
+ }
return 0;
}
diff --git a/src/basic/util.h b/src/basic/util.h
index 286db05159..1c032c15c9 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -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);
diff --git a/src/core/automount.c b/src/core/automount.c
index 5dc6fd98e7..7c55d7bc49 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -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);
diff --git a/src/core/busname.c b/src/core/busname.c
index de2a21ccde..bbe61af4f0 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -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");
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 9c34928052..25cc6962f9 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -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
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 973a60187d..9dfca14914 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -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);
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index fc50fafaad..0f54c6b84b 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -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) {
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 00372b92b4..d48b0ca69d 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -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;
@@ -1571,7 +1565,7 @@ static int reply_unit_file_changes_and_free(
unsigned i;
int r;
- if (n_changes > 0) {
+ if (unit_file_changes_have_modification(changes, n_changes)) {
r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
if (r < 0)
log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
@@ -1591,15 +1585,19 @@ static int reply_unit_file_changes_and_free(
if (r < 0)
goto fail;
- for (i = 0; i < n_changes; i++) {
- r = sd_bus_message_append(
- reply, "(sss)",
- unit_file_change_type_to_string(changes[i].type),
- changes[i].path,
- changes[i].source);
- if (r < 0)
- goto fail;
- }
+ for (i = 0; i < n_changes; i++)
+ if (changes[i].type >= 0) {
+ const char *change = unit_file_change_type_to_string(changes[i].type);
+ assert(change != NULL);
+
+ r = sd_bus_message_append(
+ reply, "(sss)",
+ change,
+ changes[i].path,
+ changes[i].source);
+ if (r < 0)
+ goto fail;
+ }
r = sd_bus_message_close_container(reply);
if (r < 0)
@@ -1613,6 +1611,58 @@ fail:
return r;
}
+/* Create an error reply, using the error information from changes[]
+ * if possible, and fall back to generating an error from error code c.
+ * The error message only describes the first error.
+ *
+ * Coordinate with unit_file_dump_changes() in install.c.
+ */
+static int install_error(
+ sd_bus_error *error,
+ int c,
+ UnitFileChange *changes,
+ unsigned n_changes) {
+ int r;
+ unsigned i;
+ assert(c < 0);
+
+ for (i = 0; i < n_changes; i++)
+ switch(changes[i].type) {
+ case 0 ... INT_MAX:
+ continue;
+ case -EEXIST:
+ if (changes[i].source)
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+ "File %s already exists and is a symlink to %s.",
+ changes[i].path, changes[i].source);
+ else
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+ "File %s already exists.",
+ changes[i].path);
+ goto found;
+ case -ERFKILL:
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED,
+ "Unit file %s is masked.", changes[i].path);
+ goto found;
+ case -EADDRNOTAVAIL:
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED,
+ "Unit %s is transient or generated.", changes[i].path);
+ goto found;
+ case -ELOOP:
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED,
+ "Refusing to operate on linked unit file %s", changes[i].path);
+ goto found;
+ default:
+ r = sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path);
+ goto found;
+ }
+
+ r = c;
+ found:
+ unit_file_changes_free(changes, n_changes);
+ return r;
+}
+
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
@@ -1624,7 +1674,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 +1693,9 @@ 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");
+ r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
}
@@ -1686,7 +1731,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,26 +1759,23 @@ 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);
+ r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
}
static int method_disable_unit_files_generic(
sd_bus_message *message,
- Manager *m, const
- char *verb,
+ Manager *m,
+ const char *verb,
int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
- UnitFileScope scope;
int r, runtime;
assert(message);
@@ -1748,17 +1789,15 @@ 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);
+ r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1771,11 +1810,37 @@ 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)
+ return install_error(error, r, changes, n_changes);
+
+ 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 +1861,9 @@ 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);
+ r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1810,7 +1873,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,13 +1901,9 @@ 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);
- if (r < 0) {
- unit_file_changes_free(changes, n_changes);
- return r;
- }
+ r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes);
+ if (r < 0)
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1855,10 +1913,8 @@ 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;
+ char *target, *type;
UnitDependency dep;
assert(message);
@@ -1882,13 +1938,9 @@ 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");
+ r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1924,7 +1976,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 +2077,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),
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index bc121b83a2..a0e61b023e 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -156,7 +156,7 @@ static int property_get_next_elapse_monotonic(
usec_t a, b;
a = now(CLOCK_MONOTONIC);
- b = now(CLOCK_BOOTTIME);
+ b = now(clock_boottime_or_monotonic());
if (t->next_elapse_monotonic_or_boottime + a > b)
x = t->next_elapse_monotonic_or_boottime + a - b;
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index b351f6a2c2..c507265070 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -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;
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 413489373f..263955d874 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -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 */
diff --git a/src/core/device.c b/src/core/device.c
index 0671620a3e..d01bec53d8 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -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;
diff --git a/src/core/failure-action.c b/src/core/failure-action.c
index bb2bc3f399..ddae46190f 100644
--- a/src/core/failure-action.c
+++ b/src/core/failure-action.c
@@ -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:
diff --git a/src/core/job.c b/src/core/job.c
index 5557a6a942..d9c5669c9f 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -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))
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 22b71b6f5e..f83fa09301 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -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,
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
index d8a4aefbb3..942d26724e 100644
--- a/src/core/load-dropin.h
+++ b/src/core/load-dropin.h
@@ -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);
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index d078924c5b..c4566f7709 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -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;
@@ -2847,11 +2847,12 @@ int config_parse_device_allow(
void *data,
void *userdata) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *path = NULL, *t = NULL;
CGroupContext *c = data;
CGroupDeviceAllow *a;
- const char *m;
+ const char *m = NULL;
size_t n;
+ int r;
if (isempty(rvalue)) {
while (c->device_allow)
@@ -2860,8 +2861,16 @@ int config_parse_device_allow(
return 0;
}
- n = strcspn(rvalue, WHITESPACE);
- path = strndup(rvalue, n);
+ r = unit_full_printf(userdata, rvalue, &t);
+ if(r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to resolve specifiers in %s, ignoring: %m",
+ rvalue);
+ }
+
+ n = strcspn(t, WHITESPACE);
+
+ path = strndup(t, n);
if (!path)
return log_oom();
@@ -2872,7 +2881,7 @@ int config_parse_device_allow(
return 0;
}
- m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+ m = t + n + strspn(t + n, WHITESPACE);
if (isempty(m))
m = "rwm";
@@ -3574,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
@@ -3620,10 +3629,12 @@ static int load_from_path(Unit *u, const char *path) {
if (fstat(fileno(f), &st) < 0)
return -errno;
- if (null_or_empty(&st))
+ if (null_or_empty(&st)) {
u->load_state = UNIT_MASKED;
- else {
+ u->fragment_mtime = 0;
+ } else {
u->load_state = UNIT_LOADED;
+ u->fragment_mtime = timespec_load(&st.st_mtim);
/* Now, parse the file contents */
r = config_parse(u->id, filename, f,
@@ -3638,8 +3649,6 @@ static int load_from_path(Unit *u, const char *path) {
u->fragment_path = filename;
filename = NULL;
- u->fragment_mtime = timespec_load(&st.st_mtim);
-
if (u->source_path) {
if (stat(u->source_path, &st) >= 0)
u->source_mtime = timespec_load(&st.st_mtim);
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 7b25349c07..9de528b6cf 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -261,10 +261,10 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
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);
+ if (r < 0) {
+ (void) unlink(run_machine_id);
+ return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
+ }
}
/* And now, let's mount it over */
diff --git a/src/core/main.c b/src/core/main.c
index 56df32426a..8dfb3928de 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -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");
@@ -1336,7 +1338,7 @@ int main(int argc, char *argv[]) {
saved_argv = argv;
saved_argc = argc;
- log_show_color(isatty(STDERR_FILENO) > 0);
+ log_show_color(colors_enabled());
log_set_upgrade_syslog_to_journal(true);
/* Disable the umask logic */
@@ -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;
diff --git a/src/core/manager.c b/src/core/manager.c
index e739795e70..5601770670 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -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);
- dual_timestamp_get(&m->generators_start_timestamp);
- r = manager_run_generators(m);
- dual_timestamp_get(&m->generators_finish_timestamp);
+ 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;
- 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);
+ dual_timestamp_get(&m->generators_start_timestamp);
+ r = manager_run_generators(m);
+ dual_timestamp_get(&m->generators_finish_timestamp);
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);
- /* Find new unit paths */
- q = manager_run_generators(m);
+ q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
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);
+ /* Find new unit paths */
+ q = manager_run_generators(m);
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");
}
diff --git a/src/core/manager.h b/src/core/manager.h
index 9803f73129..17f84e6963 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -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);
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 32fe51c67e..40fc548b42 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -375,6 +375,7 @@ int mount_setup(bool loaded_policy) {
before_relabel = now(CLOCK_MONOTONIC);
nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
after_relabel = now(CLOCK_MONOTONIC);
diff --git a/src/core/mount.c b/src/core/mount.c
index 0fd880df5d..632c5c824c 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -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);
@@ -377,8 +376,7 @@ static int mount_add_quota_links(Mount *m) {
static bool should_umount(Mount *m) {
MountParameters *p;
- if (path_equal(m->where, "/") ||
- path_equal(m->where, "/usr") ||
+ if (PATH_IN_SET(m->where, "/", "/usr") ||
path_startswith(m->where, "/run/initramfs"))
return false;
@@ -400,7 +398,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
@@ -409,8 +407,7 @@ static int mount_add_default_dependencies(Mount *m) {
* Also, don't bother with anything mounted below virtual
* file systems, it's also going to be virtual, and hence
* not worth the effort. */
- if (path_equal(m->where, "/") ||
- path_equal(m->where, "/usr") ||
+ if (PATH_IN_SET(m->where, "/", "/usr") ||
path_startswith(m->where, "/run/initramfs") ||
path_startswith(m->where, "/proc") ||
path_startswith(m->where, "/sys") ||
@@ -1396,7 +1393,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 +1421,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
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 6a7a37ee92..f78eedbd6e 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -176,6 +176,10 @@
<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"/>
<allow send_destination="org.freedesktop.systemd1"
diff --git a/src/core/path.c b/src/core/path.c
index 6ac9b8b90d..5e7b3eb234 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -110,16 +110,14 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
} else {
exists = true;
- /* Path exists, we don't need to watch parent
- too closely. */
+ /* Path exists, we don't need to watch parent too closely. */
if (oldslash) {
char *cut2 = oldslash + (oldslash == s->path);
char tmp2 = *cut2;
*cut2 = '\0';
- inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
- /* Error is ignored, the worst can happen is
- we get spurious events. */
+ (void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
+ /* Error is ignored, the worst can happen is we get spurious events. */
*cut2 = tmp2;
}
@@ -320,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;
diff --git a/src/core/scope.c b/src/core/scope.c
index 361695c3f9..7078d1f7e9 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -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);
diff --git a/src/core/service.c b/src/core/service.c
index 5d58b0b752..58084e2f82 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -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. */
@@ -832,7 +832,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
return 0;
}
-static int service_search_main_pid(Service *s) {
+static void service_search_main_pid(Service *s) {
pid_t pid = 0;
int r;
@@ -841,30 +841,24 @@ static int service_search_main_pid(Service *s) {
/* If we know it anyway, don't ever fallback to unreliable
* heuristics */
if (s->main_pid_known)
- return 0;
+ return;
if (!s->guess_main_pid)
- return 0;
+ return;
assert(s->main_pid <= 0);
- r = unit_search_main_pid(UNIT(s), &pid);
- if (r < 0)
- return r;
+ if (unit_search_main_pid(UNIT(s), &pid) < 0)
+ return;
log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
- r = service_set_main_pid(s, pid);
- if (r < 0)
- return r;
+ if (service_set_main_pid(s, pid) < 0)
+ return;
r = unit_watch_pid(UNIT(s), pid);
- if (r < 0) {
+ if (r < 0)
/* FIXME: we need to do something here */
log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
- return r;
- }
-
- return 0;
}
static void service_set_state(Service *s, ServiceState state) {
@@ -926,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
@@ -1217,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;
@@ -2729,7 +2723,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
}
} else
- (void) service_search_main_pid(s);
+ service_search_main_pid(s);
service_enter_start_post(s);
break;
@@ -2751,16 +2745,15 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
}
} else
- (void) service_search_main_pid(s);
+ service_search_main_pid(s);
service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_RELOAD:
- if (f == SERVICE_SUCCESS) {
- service_load_pid_file(s, true);
- (void) service_search_main_pid(s);
- }
+ if (f == SERVICE_SUCCESS)
+ if (service_load_pid_file(s, true) < 0)
+ service_search_main_pid(s);
s->reload_result = f;
service_enter_running(s, SERVICE_SUCCESS);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 6296b4c94a..e14755d84e 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -202,7 +202,7 @@ int main(int argc, char *argv[]) {
goto error;
}
- cg_get_root_path(&cgroup);
+ (void) cg_get_root_path(&cgroup);
use_watchdog = !!getenv("WATCHDOG_USEC");
@@ -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");
}
}
diff --git a/src/core/slice.c b/src/core/slice.c
index 667f61bde5..63a77c9bca 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -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)
diff --git a/src/core/socket.c b/src/core/socket.c
index dd515a17a5..65da0e3c5e 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -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;
diff --git a/src/core/swap.c b/src/core/swap.c
index 11506d9ecb..c6502eb821 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -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)
diff --git a/src/core/timer.c b/src/core/timer.c
index 3d0bae16e5..b286b714fa 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -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)
@@ -320,7 +320,7 @@ static usec_t monotonic_to_boottime(usec_t t) {
if (t <= 0)
return 0;
- a = now(CLOCK_BOOTTIME);
+ a = now(clock_boottime_or_monotonic());
b = now(CLOCK_MONOTONIC);
if (t + a > b)
diff --git a/src/core/transaction.c b/src/core/transaction.c
index c894001cf9..d5370b2a14 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -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", */
@@ -939,7 +939,7 @@ int transaction_add_job_and_dependencies(
if (r < 0) {
/* unit masked, job type not applicable and unit not found are not considered as errors. */
log_unit_full(dep,
- IN_SET(r, -ESHUTDOWN, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
+ IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
r, "Cannot add dependency job, ignoring: %s",
bus_error_message(e, r));
sd_bus_error_free(e);
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index fc057d965c..f11df42af3 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -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;
diff --git a/src/core/unit.c b/src/core/unit.c
index af38beb0c3..c60ae2be9d 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -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;
- (void) unlink(*i);
+ 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;
- p = dirname_malloc(*i);
- if (p)
- (void) rmdir(p);
+ (void) unlink(*i);
+ (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;
@@ -2493,12 +2518,11 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
return -EBUSY;
match = strjoina("type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "arg0='", name, "'",
- NULL);
+ "sender='org.freedesktop.DBus',"
+ "path='/org/freedesktop/DBus',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "arg0='", name, "'");
return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
}
@@ -2884,7 +2908,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;
@@ -2924,34 +2948,36 @@ int unit_coldplug(Unit *u) {
return 0;
}
+static bool fragment_mtime_changed(const char *path, usec_t mtime) {
+ struct stat st;
+
+ if (!path)
+ return false;
+
+ if (stat(path, &st) < 0)
+ /* What, cannot access this anymore? */
+ return true;
+
+ if (mtime > 0)
+ /* For non-empty files check the mtime */
+ return timespec_load(&st.st_mtim) != mtime;
+ else if (!null_or_empty(&st))
+ /* For masked files check if they are still so */
+ return true;
+
+ return false;
+}
+
bool unit_need_daemon_reload(Unit *u) {
_cleanup_strv_free_ char **t = NULL;
char **path;
- struct stat st;
unsigned loaded_cnt, current_cnt;
assert(u);
- if (u->fragment_path) {
- zero(st);
- if (stat(u->fragment_path, &st) < 0)
- /* What, cannot access this anymore? */
- return true;
-
- if (u->fragment_mtime > 0 &&
- timespec_load(&st.st_mtim) != u->fragment_mtime)
- return true;
- }
-
- if (u->source_path) {
- zero(st);
- if (stat(u->source_path, &st) < 0)
- return true;
-
- if (u->source_mtime > 0 &&
- timespec_load(&st.st_mtim) != u->source_mtime)
- return true;
- }
+ if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) ||
+ fragment_mtime_changed(u->source_path, u->source_mtime))
+ return true;
(void) unit_find_dropin_paths(u, &t);
loaded_cnt = strv_length(t);
@@ -2962,21 +2988,15 @@ bool unit_need_daemon_reload(Unit *u) {
return false;
if (strv_overlap(u->dropin_paths, t)) {
- STRV_FOREACH(path, u->dropin_paths) {
- zero(st);
- if (stat(*path, &st) < 0)
- return true;
-
- if (u->dropin_mtime > 0 &&
- timespec_load(&st.st_mtim) > u->dropin_mtime)
+ STRV_FOREACH(path, u->dropin_paths)
+ if (fragment_mtime_changed(*path, u->dropin_mtime))
return true;
- }
return false;
- } else
- return true;
- } else
- return true;
+ }
+ }
+
+ return true;
}
void unit_reset_failed(Unit *u) {
@@ -3044,8 +3064,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;
@@ -3162,7 +3181,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);
@@ -3178,7 +3197,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));
@@ -3229,7 +3248,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);
@@ -3241,7 +3260,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) ||
@@ -3319,59 +3338,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;
+
+ 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 = write_drop_in(dir, u->id, 50, name, data);
+ r = drop_in_file(dir, u->id, 50, name, &p, &q);
if (r < 0)
return r;
- r = drop_in_file(dir, u->id, 50, name, &p, &q);
+ (void) mkdir_p(p, 0755);
+ r = write_string_file_atomic_label(q, prefixed);
if (r < 0)
return r;
- r = strv_extend(&u->dropin_paths, q);
+ r = strv_push(&u->dropin_paths, q);
if (r < 0)
return r;
+ q = NULL;
- strv_sort(u->dropin_paths);
strv_uniq(u->dropin_paths);
u->dropin_mtime = now(CLOCK_REALTIME);
@@ -3402,7 +3424,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);
@@ -3414,9 +3436,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);
return unit_write_drop_in(u, mode, name, ndata);
}
@@ -3444,24 +3464,51 @@ 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;
}
diff --git a/src/core/unit.h b/src/core/unit.h
index 601e763ce2..cfdac852a5 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -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;
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 085909c20c..2bbb958861 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -49,6 +49,7 @@
#include "journald-native.h"
#include "log.h"
#include "macro.h"
+#include "missing.h"
#include "mkdir.h"
#include "parse-util.h"
#include "process-util.h"
@@ -212,6 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
#define filename_escape(s) xescape((s), "./ ")
+static inline const char *coredump_tmpfile_name(const char *s) {
+ return s ? s : "(unnamed temporary file)";
+}
+
static int fix_permissions(
int fd,
const char *filename,
@@ -220,7 +225,6 @@ static int fix_permissions(
uid_t uid) {
assert(fd >= 0);
- assert(filename);
assert(target);
assert(context);
@@ -230,10 +234,20 @@ static int fix_permissions(
(void) fix_xattr(fd, context);
if (fsync(fd) < 0)
- return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
+ return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
+
+ if (filename) {
+ if (rename(filename, target) < 0)
+ return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
+ } else {
+ _cleanup_free_ char *proc_fd_path = NULL;
- if (rename(filename, target) < 0)
- return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
+ if (asprintf(&proc_fd_path, "/proc/self/fd/%d", fd) < 0)
+ return log_oom();
+
+ if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
+ return log_error_errno(errno, "Failed to create coredump %s: %m", target);
+ }
return 0;
}
@@ -294,6 +308,33 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
return 0;
}
+static int open_coredump_tmpfile(const char *target, char **ret_filename) {
+ _cleanup_free_ char *tmp = NULL;
+ int fd;
+ int r;
+
+ assert(target);
+ assert(ret_filename);
+
+ fd = open("/var/lib/systemd/coredump", O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0640);
+ if (fd < 0) {
+ log_debug_errno(errno, "Failed to use O_TMPFILE: %m");
+
+ r = tempfn_random(target, NULL, &tmp);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine temporary file name: %m");
+
+ fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
+ }
+
+ *ret_filename = tmp;
+ tmp = NULL;
+
+ return fd;
+}
+
static int save_external_coredump(
const char *context[_CONTEXT_MAX],
int input_fd,
@@ -335,15 +376,11 @@ static int save_external_coredump(
if (r < 0)
return log_error_errno(r, "Failed to determine coredump file name: %m");
- r = tempfn_random(fn, NULL, &tmp);
- if (r < 0)
- return log_error_errno(r, "Failed to determine temporary file name: %m");
-
mkdir_p_label("/var/lib/systemd/coredump", 0755);
- fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+ fd = open_coredump_tmpfile(fn, &tmp);
if (fd < 0)
- return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
+ return fd;
r = copy_bytes(input_fd, fd, max_size, false);
if (r == -EFBIG) {
@@ -358,12 +395,12 @@ static int save_external_coredump(
}
if (fstat(fd, &st) < 0) {
- log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
+ log_error_errno(errno, "Failed to fstat coredump %s: %m", coredump_tmpfile_name(tmp));
goto fail;
}
if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
- log_error_errno(errno, "Failed to seek on %s: %m", tmp);
+ log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp));
goto fail;
}
@@ -381,21 +418,13 @@ static int save_external_coredump(
goto uncompressed;
}
- r = tempfn_random(fn_compressed, NULL, &tmp_compressed);
- if (r < 0) {
- log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
+ fd_compressed = open_coredump_tmpfile(fn_compressed, &tmp_compressed);
+ if (fd_compressed < 0)
goto uncompressed;
- }
-
- fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
- if (fd_compressed < 0) {
- log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
- goto uncompressed;
- }
r = compress_stream(fd, fd_compressed, -1);
if (r < 0) {
- log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
+ log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed));
goto fail_compressed;
}
@@ -404,7 +433,8 @@ static int save_external_coredump(
goto fail_compressed;
/* OK, this worked, we can get rid of the uncompressed version now */
- unlink_noerrno(tmp);
+ if (tmp)
+ unlink_noerrno(tmp);
*ret_filename = fn_compressed; /* compressed */
*ret_node_fd = fd_compressed; /* compressed */
@@ -417,7 +447,8 @@ static int save_external_coredump(
return 0;
fail_compressed:
- (void) unlink(tmp_compressed);
+ if (tmp_compressed)
+ (void) unlink(tmp_compressed);
}
uncompressed:
@@ -438,7 +469,8 @@ uncompressed:
return 0;
fail:
- (void) unlink(tmp);
+ if (tmp)
+ (void) unlink(tmp);
return r;
}
@@ -1095,7 +1127,7 @@ static int process_kernel(int argc, char* argv[]) {
IOVEC_SET_STRING(iovec[n_iovec++], core_environ);
}
- core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL);
+ core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp);
IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
diff --git a/src/import/curl-util.c b/src/import/curl-util.c
index a04c8c49ff..6990c47f48 100644
--- a/src/import/curl-util.c
+++ b/src/import/curl-util.c
@@ -137,7 +137,7 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v
if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0)
return -1;
- sd_event_source_set_description(io, "curl-io");
+ (void) sd_event_source_set_description(io, "curl-io");
r = hashmap_put(g->ios, FD_TO_PTR(s), io);
if (r < 0) {
@@ -204,7 +204,7 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata
if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0)
return -1;
- sd_event_source_set_description(g->timer, "curl-timer");
+ (void) sd_event_source_set_description(g->timer, "curl-timer");
}
return 0;
diff --git a/src/import/pull-job.h b/src/import/pull-job.h
index 998857035a..3a152a50e3 100644
--- a/src/import/pull-job.h
+++ b/src/import/pull-job.h
@@ -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;
diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c
index 8956eb1d58..612b10f3a9 100644
--- a/src/journal/fsprg.c
+++ b/src/journal/fsprg.c
@@ -58,7 +58,7 @@ static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
gcry_mpi_t h;
unsigned len;
- gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL);
+ assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
len = (gcry_mpi_get_nbits(h) + 7) / 8;
assert(len <= buflen);
assert(gcry_mpi_cmp_ui(h, 0) >= 0);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 2939322925..b1d1bf9e14 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -492,38 +492,36 @@ static void server_cache_hostname(Server *s) {
}
static bool shall_try_append_again(JournalFile *f, int r) {
-
- /* -E2BIG Hit configured limit
- -EFBIG Hit fs limit
- -EDQUOT Quota limit hit
- -ENOSPC Disk full
- -EIO I/O error of some kind (mmap)
- -EHOSTDOWN Other machine
- -EBUSY Unclean shutdown
- -EPROTONOSUPPORT Unsupported feature
- -EBADMSG Corrupted
- -ENODATA Truncated
- -ESHUTDOWN Already archived
- -EIDRM Journal file has been deleted */
-
- if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
+ switch(r) {
+ case -E2BIG: /* Hit configured limit */
+ case -EFBIG: /* Hit fs limit */
+ case -EDQUOT: /* Quota limit hit */
+ case -ENOSPC: /* Disk full */
log_debug("%s: Allocation limit reached, rotating.", f->path);
- else if (r == -EHOSTDOWN)
+ return true;
+ case -EIO: /* I/O error of some kind (mmap) */
+ log_warning("%s: IO error, rotating.", f->path);
+ return true;
+ case -EHOSTDOWN: /* Other machine */
log_info("%s: Journal file from other machine, rotating.", f->path);
- else if (r == -EBUSY)
+ return true;
+ case -EBUSY: /* Unclean shutdown */
log_info("%s: Unclean shutdown, rotating.", f->path);
- else if (r == -EPROTONOSUPPORT)
+ return true;
+ case -EPROTONOSUPPORT: /* Unsupported feature */
log_info("%s: Unsupported feature, rotating.", f->path);
- else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
+ return true;
+ case -EBADMSG: /* Corrupted */
+ case -ENODATA: /* Truncated */
+ case -ESHUTDOWN: /* Already archived */
log_warning("%s: Journal file corrupted, rotating.", f->path);
- else if (r == -EIO)
- log_warning("%s: IO error, rotating.", f->path);
- else if (r == -EIDRM)
+ return true;
+ case -EIDRM: /* Journal file has been deleted */
log_warning("%s: Journal file has been deleted, rotating.", f->path);
- else
+ return true;
+ default:
return false;
-
- return true;
+ }
}
static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) {
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
index 6370061daf..02e3bf904c 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -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),
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 464834979a..c8f369cb78 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -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"
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index e860876c12..52128e7b5c 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -678,6 +678,7 @@ int bus_get_name_creds_kdbus(
(mask & (SD_BUS_CREDS_PPID|
SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -795,6 +796,7 @@ static int bus_get_name_creds_dbus1(
((mask & SD_BUS_CREDS_AUGMENT) &&
(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -947,6 +949,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **
(mask & (SD_BUS_CREDS_PPID|
SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 862f26aad7..04da94e7e3 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -1778,7 +1778,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
r = bus_write_message(bus, m, hint_sync_call, &idx);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
return -ECONNRESET;
}
@@ -2083,7 +2083,7 @@ _public_ int sd_bus_call(
r = bus_read_message(bus, false, 0);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = -ECONNRESET;
}
@@ -2116,7 +2116,7 @@ _public_ int sd_bus_call(
r = dispatch_wqueue(bus);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = -ECONNRESET;
}
@@ -2766,7 +2766,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_OPENING:
r = bus_socket_process_opening(bus);
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = 1;
} else if (r < 0)
@@ -2777,7 +2777,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_AUTHENTICATING:
r = bus_socket_process_authenticating(bus);
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = 1;
} else if (r < 0)
@@ -2791,7 +2791,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_RUNNING:
case BUS_HELLO:
r = process_running(bus, hint_priority, priority, ret);
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = 1;
@@ -2914,7 +2914,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
for (;;) {
r = dispatch_wqueue(bus);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
return -ECONNRESET;
}
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 841358ed03..79b98c293c 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -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;
@@ -2528,7 +2527,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
dual_timestamp_get(&e->timestamp);
- e->timestamp_boottime = now(CLOCK_BOOTTIME);
+ e->timestamp_boottime = now(clock_boottime_or_monotonic());
for (i = 0; i < m; i++) {
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index a5758bb516..3a4bac2ced 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -95,12 +95,43 @@ static const NLType rtnl_link_info_data_macvlan_types[] = {
};
static const NLType rtnl_link_info_data_bridge_types[] = {
- [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_vlan_types[] = {
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index 37585048b8..d8303e2e69 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -579,9 +579,10 @@ static void resolve_free(sd_resolve *resolve) {
(void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
}
- /* Now terminate them and wait until they are gone. */
+ /* Now terminate them and wait until they are gone.
+ If we get an error than most likely the thread already exited. */
for (i = 0; i < resolve->n_valid_workers; i++)
- pthread_join(resolve->workers[i], NULL);
+ (void) pthread_join(resolve->workers[i], NULL);
/* Close all communication channels */
for (i = 0; i < _FD_MAX; i++)
diff --git a/src/locale/localed.c b/src/locale/localed.c
index 46405ca68a..3b22a582ac 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -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 */
+
+ 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;
- ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
+ 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 ||
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index ff9170683b..0f8862c0d9 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -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(
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index e088225beb..a8b1d5943d 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -513,7 +513,7 @@ static int session_start_scope(Session *s) {
if (!scope)
return log_oom();
- description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
+ description = strjoina("Session ", s->id, " of user ", s->user->name);
r = manager_start_scope(
s->manager,
@@ -797,7 +797,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
/* Graphical sessions should really implement a real
* idle hint logic */
- if (s->display)
+ if (SESSION_TYPE_IS_GRAPHICAL(s->type))
goto dont_know;
/* For sessions with an explicitly configured tty, let's check
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index fd98c7beca..b73f9ea69e 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -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);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index c5bbf2fbde..ab54d9e934 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -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(
@@ -729,7 +730,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
return r;
/* Name and mode */
- unit = strjoina("container-shell@", p, ".service", NULL);
+ unit = strjoina("container-shell@", p, ".service");
r = sd_bus_message_append(tm, "ss", unit, "fail");
if (r < 0)
return r;
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 1d3264a1de..c370ed57ec 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -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"
@@ -2358,7 +2402,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
" --uid=USER Specify user ID to invoke shell as\n"
- " --setenv=VAR=VALUE Add an environment variable for shell\n"
+ " -E --setenv=VAR=VALUE Add an environment variable for shell\n"
" --read-only Create read-only bind mount\n"
" --mkdir Create directory before bind mounting, if missing\n"
" -n --lines=INTEGER Number of journal entries to show\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"
@@ -2425,7 +2470,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE,
ARG_FORMAT,
ARG_UID,
- ARG_SETENV,
};
static const struct option options[] = {
@@ -2451,7 +2495,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "force", no_argument, NULL, ARG_FORCE },
{ "format", required_argument, NULL, ARG_FORMAT },
{ "uid", required_argument, NULL, ARG_UID },
- { "setenv", required_argument, NULL, ARG_SETENV },
+ { "setenv", required_argument, NULL, 'E' },
{}
};
@@ -2579,7 +2623,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_uid = optarg;
break;
- case ARG_SETENV:
+ case 'E':
if (!env_assignment_is_valid(optarg)) {
log_error("Environment assignment invalid: %s", optarg);
return -EINVAL;
@@ -2635,6 +2679,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 },
{}
};
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 20894433e7..c9639c3cf2 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -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),
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index d9d487d805..ebc6c9eb9e 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -148,8 +148,12 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
for (;;) {
if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
_cleanup_free_ char *s = NULL;
+ int r;
+
+ r = in_addr_to_string(p->family, &u, &s);
+ if (r < 0)
+ return r;
- in_addr_to_string(p->family, &u, &s);
log_debug("Found range %s/%u", strna(s), prefixlen);
*found = u;
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 0589ebf227..c5b61abc9e 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -57,6 +57,10 @@ static int link_set_dhcp_routes(Link *link) {
assert(link);
assert(link->dhcp_lease);
+ assert(link->network);
+
+ if (!link->network->dhcp_use_routes)
+ return 0;
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r < 0 && r != -ENODATA)
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 88b3cbe90a..0fb3aa6c43 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -99,6 +99,15 @@ static bool link_ipv6ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV6;
}
+static bool link_ipv6_enabled(Link *link) {
+ assert(link);
+
+ if (!socket_ipv6_is_supported())
+ return false;
+
+ return link_dhcp6_enabled(link) || link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
+}
+
static bool link_lldp_rx_enabled(Link *link) {
assert(link);
@@ -165,6 +174,21 @@ static bool link_ipv6_forward_enabled(Link *link) {
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
}
+static bool link_proxy_arp_enabled(Link *link) {
+ assert(link);
+
+ if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (!link->network)
+ return false;
+
+ if (link->network->proxy_arp < 0)
+ return false;
+
+ return true;
+}
+
static bool link_ipv6_accept_ra_enabled(Link *link) {
assert(link);
@@ -203,6 +227,31 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
return link->network->ipv6_privacy_extensions;
}
+static int link_enable_ipv6(Link *link) {
+ const char *p = NULL;
+ bool disabled;
+ int r;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ disabled = !link_ipv6_enabled(link);
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6");
+
+ r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", disabled ? "disable" : "enable", link->ifname);
+ else {
+ if (disabled)
+ log_link_info(link, "IPv6 disabled for interface: %m");
+ else
+ log_link_info(link, "IPv6 enabled for interface: %m");
+ }
+
+ return 0;
+}
+
void link_update_operstate(Link *link) {
LinkOperationalState operstate;
assert(link);
@@ -1039,6 +1088,22 @@ static int link_set_bridge_fdb(Link *const link) {
return r;
}
+static int link_set_proxy_arp(Link *const link) {
+ const char *p = NULL;
+ int r;
+
+ if (!link_proxy_arp_enabled(link))
+ return 0;
+
+ p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp");
+
+ r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
+
+ return 0;
+}
+
static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -1479,7 +1544,21 @@ static int link_up(Link *link) {
return log_link_error_errno(link, r, "Could not set MAC address: %m");
}
+ /* If IPv6 not configured (no static IPv6 address and neither DHCPv6 nor IPv6LL is enabled)
+ for this interface then disable IPv6 else enable it. */
+ (void) link_enable_ipv6(link);
+
if (link->network->mtu) {
+ /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
+ on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */
+ if (link_ipv6_enabled(link) && link->network->mtu < IPV6_MIN_MTU) {
+
+ log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as "
+ "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m");
+
+ link->network->mtu = IPV6_MIN_MTU;
+ }
+
r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu);
if (r < 0)
return log_link_error_errno(link, r, "Could not set MTU: %m");
@@ -1489,7 +1568,7 @@ static int link_up(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
- if (socket_ipv6_is_supported()) {
+ if (link_ipv6_enabled(link)) {
/* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
r = sd_netlink_message_open_container(req, AF_INET6);
if (r < 0)
@@ -2167,6 +2246,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_proxy_arp(link);
+ if (r < 0)
+ return r;
+
r = link_set_ipv4_forward(link);
if (r < 0)
return r;
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
index c940e63052..6bde04bc32 100644
--- a/src/network/networkd-lldp-tx.c
+++ b/src/network/networkd-lldp-tx.c
@@ -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;
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index cdcd08f057..3f91b2eaea 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -89,6 +89,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
}
+ if (b->mcast_querier >= 0) {
+ r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_QUERIER, b->mcast_querier);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
@@ -106,8 +112,19 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return r;
}
+static void bridge_init(NetDev *n) {
+ Bridge *b;
+
+ b = BRIDGE(n);
+
+ assert(b);
+
+ b->mcast_querier = -1;
+}
+
const NetDevVTable bridge_vtable = {
.object_size = sizeof(Bridge),
+ .init = bridge_init,
.sections = "Match\0NetDev\0Bridge\0",
.post_create = netdev_bridge_post_create,
.create_type = NETDEV_CREATE_MASTER,
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index 27f26f7870..3f6f1d0502 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -26,6 +26,8 @@ typedef struct Bridge Bridge;
struct Bridge {
NetDev meta;
+ int mcast_querier;
+
usec_t forward_delay;
usec_t hello_time;
usec_t max_age;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 8f506af092..15a787a9e3 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -92,3 +92,4 @@ Bond.LearnPacketIntervalSec, config_parse_sec, 0,
Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time)
Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
+Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 9793938080..1da99cd5bc 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -61,6 +61,7 @@ Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions,
Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit)
+Network.ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 5946ba18dc..07f8fb028f 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -132,6 +132,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->ipv6_dad_transmits = -1;
network->ipv6_hop_limit = -1;
network->duid_type = _DUID_TYPE_INVALID;
+ network->proxy_arp = -1;
r = config_parse(NULL, filename, file,
"Match\0"
@@ -398,6 +399,19 @@ int network_apply(Manager *manager, Network *network, Link *link) {
return 0;
}
+bool network_has_static_ipv6_addresses(Network *network) {
+ Address *address;
+
+ assert(network);
+
+ LIST_FOREACH(addresses, address, network->static_addresses) {
+ if (address->family == AF_INET6)
+ return true;
+ }
+
+ return false;
+}
+
int config_parse_netdev(const char *unit,
const char *filename,
unsigned line,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 5400a8bc9d..15417f4828 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -139,6 +139,7 @@ struct Network {
int ipv6_accept_ra;
int ipv6_dad_transmits;
int ipv6_hop_limit;
+ int proxy_arp;
union in_addr_union ipv6_token;
IPv6PrivacyExtensions ipv6_privacy_extensions;
@@ -185,6 +186,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret);
int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
int network_apply(Manager *manager, Network *network, Link *link);
+bool network_has_static_ipv6_addresses(Network *network);
+
int config_parse_netdev(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_tunnel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index e065a5a5a9..ab9b777d9a 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -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;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index eb89916b7e..a07f148ef6 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -64,6 +64,7 @@
#include "hostname-util.h"
#include "log.h"
#include "loopback-setup.h"
+#include "machine-id-setup.h"
#include "machine-image.h"
#include "macro.h"
#include "missing.h"
@@ -249,7 +250,7 @@ static void help(void) {
" the container\n"
" --overlay-ro=PATH[:PATH...]:PATH\n"
" Similar, but creates a read-only overlay mount\n"
- " --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
+ " -E --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
" --share-system Share system namespaces with host\n"
" --register=BOOLEAN Register container as machine\n"
" --keep-unit Do not register a scope for the machine, reuse\n"
@@ -332,7 +333,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_TMPFS,
ARG_OVERLAY,
ARG_OVERLAY_RO,
- ARG_SETENV,
ARG_SHARE_SYSTEM,
ARG_REGISTER,
ARG_KEEP_UNIT,
@@ -373,7 +373,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO },
{ "machine", required_argument, NULL, 'M' },
{ "slice", required_argument, NULL, 'S' },
- { "setenv", required_argument, NULL, ARG_SETENV },
+ { "setenv", required_argument, NULL, 'E' },
{ "selinux-context", required_argument, NULL, 'Z' },
{ "selinux-apifs-context", required_argument, NULL, 'L' },
{ "quiet", no_argument, NULL, 'q' },
@@ -710,7 +710,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
- case ARG_SETENV: {
+ case 'E': {
char **n;
if (!env_assignment_is_valid(optarg)) {
@@ -1375,11 +1375,11 @@ static int setup_hostname(void) {
}
static int setup_journal(const char *directory) {
- sd_id128_t machine_id, this_id;
+ sd_id128_t this_id;
_cleanup_free_ char *b = NULL, *d = NULL;
- const char *etc_machine_id, *p, *q;
+ const char *p, *q;
bool try;
- char *id;
+ char id[33];
int r;
/* Don't link journals in ephemeral mode */
@@ -1391,28 +1391,11 @@ static int setup_journal(const char *directory) {
try = arg_link_journal_try || arg_link_journal == LINK_AUTO;
- etc_machine_id = prefix_roota(directory, "/etc/machine-id");
-
- r = read_one_line_file(etc_machine_id, &b);
- if (r == -ENOENT && try)
- return 0;
- else if (r < 0)
- return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
-
- id = strstrip(b);
- if (isempty(id) && try)
- return 0;
-
- /* Verify validity */
- r = sd_id128_from_string(id, &machine_id);
- if (r < 0)
- return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
-
r = sd_id128_get_machine(&this_id);
if (r < 0)
return log_error_errno(r, "Failed to retrieve machine ID: %m");
- if (sd_id128_equal(machine_id, this_id)) {
+ if (sd_id128_equal(arg_uuid, this_id)) {
log_full(try ? LOG_WARNING : LOG_ERR,
"Host and machine ids are equal (%s): refusing to link journals", id);
if (try)
@@ -1432,6 +1415,8 @@ static int setup_journal(const char *directory) {
if (r < 0)
return log_error_errno(r, "Failed to create /var/log/journal: %m");
+ (void) sd_id128_to_string(arg_uuid, id);
+
p = strjoina("/var/log/journal/", id);
q = prefix_roota(directory, p);
@@ -2201,6 +2186,38 @@ static int mount_device(const char *what, const char *where, const char *directo
#endif
}
+static int setup_machine_id(const char *directory) {
+ int r;
+ const char *etc_machine_id, *t;
+ _cleanup_free_ char *s = NULL;
+
+ etc_machine_id = prefix_roota(directory, "/etc/machine-id");
+
+ r = read_one_line_file(etc_machine_id, &s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
+
+ t = strstrip(s);
+
+ if (!isempty(t)) {
+ r = sd_id128_from_string(t, &arg_uuid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
+ } else {
+ if (sd_id128_is_null(arg_uuid)) {
+ r = sd_id128_randomize(&arg_uuid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate random machine ID: %m");
+ }
+ }
+
+ r = machine_id_setup(directory, arg_uuid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to setup machine ID: %m");
+
+ return 0;
+}
+
static int mount_devices(
const char *where,
const char *root_device, bool root_device_rw,
@@ -2458,6 +2475,7 @@ static int inner_child(
FDSet *fds) {
_cleanup_free_ char *home = NULL;
+ char as_uuid[37];
unsigned n_env = 1;
const char *envp[] = {
"PATH=" DEFAULT_PATH_SPLIT_USR,
@@ -2575,12 +2593,10 @@ static int inner_child(
(asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
return log_oom();
- if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) {
- char as_uuid[37];
+ assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL));
- if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
- return log_oom();
- }
+ if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
+ return log_oom();
if (fdset_size(fds) > 0) {
r = fdset_cloexec(fds, false);
@@ -2648,7 +2664,8 @@ static int inner_child(
execvpe(arg_parameters[0], arg_parameters, env_use);
else {
if (!arg_chdir)
- chdir(home ?: "/root");
+ /* If we cannot change the directory, we'll end up in /, that is expected. */
+ (void) chdir(home ?: "/root");
execle("/bin/bash", "-bash", NULL, env_use);
execle("/bin/sh", "-sh", NULL, env_use);
@@ -2669,6 +2686,7 @@ static int outer_child(
bool interactive,
bool secondary,
int pid_socket,
+ int uuid_socket,
int kmsg_socket,
int rtnl_socket,
int uid_shift_socket,
@@ -2682,6 +2700,7 @@ static int outer_child(
assert(directory);
assert(console);
assert(pid_socket >= 0);
+ assert(uuid_socket >= 0);
assert(kmsg_socket >= 0);
cg_unified_flush();
@@ -2796,6 +2815,10 @@ static int outer_child(
if (r < 0)
return r;
+ r = setup_machine_id(directory);
+ if (r < 0)
+ return r;
+
r = setup_journal(directory);
if (r < 0)
return r;
@@ -2821,6 +2844,7 @@ static int outer_child(
return log_error_errno(errno, "Failed to fork inner child: %m");
if (pid == 0) {
pid_socket = safe_close(pid_socket);
+ uuid_socket = safe_close(uuid_socket);
uid_shift_socket = safe_close(uid_shift_socket);
/* The inner child has all namespaces that are
@@ -2842,7 +2866,16 @@ static int outer_child(
return -EIO;
}
+ l = send(uuid_socket, &arg_uuid, sizeof(arg_uuid), MSG_NOSIGNAL);
+ if (l < 0)
+ return log_error_errno(errno, "Failed to send machine ID: %m");
+ if (l != sizeof(arg_uuid)) {
+ log_error("Short write while sending machine ID.");
+ return -EIO;
+ }
+
pid_socket = safe_close(pid_socket);
+ uuid_socket = safe_close(uuid_socket);
kmsg_socket = safe_close(kmsg_socket);
rtnl_socket = safe_close(rtnl_socket);
@@ -3318,7 +3351,8 @@ int main(int argc, char *argv[]) {
}
for (;;) {
- _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
+ _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 },
+ pid_socket_pair[2] = { -1, -1 }, uuid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
static const struct sigaction sa = {
@@ -3353,6 +3387,11 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uuid_socket_pair) < 0) {
+ r = log_error_errno(errno, "Failed to create id socket pair: %m");
+ goto finish;
+ }
+
if (arg_userns)
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) {
r = log_error_errno(errno, "Failed to create uid shift socket pair: %m");
@@ -3393,6 +3432,7 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
+ uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
(void) reset_all_signal_handlers();
@@ -3407,6 +3447,7 @@ int main(int argc, char *argv[]) {
interactive,
secondary,
pid_socket_pair[1],
+ uuid_socket_pair[1],
kmsg_socket_pair[1],
rtnl_socket_pair[1],
uid_shift_socket_pair[1],
@@ -3424,6 +3465,7 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
+ uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
/* Wait for the outer child. */
@@ -3448,6 +3490,18 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ /* We also retrieve container UUID in case it was generated by outer child */
+ l = recv(uuid_socket_pair[0], &arg_uuid, sizeof(arg_uuid), 0);
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read container machine ID: %m");
+ goto finish;
+ }
+ if (l != sizeof(arg_uuid)) {
+ log_error("Short read while reading container machined ID.");
+ r = EIO;
+ goto finish;
+ }
+
log_debug("Init process invoked as PID " PID_FMT, pid);
if (arg_userns) {
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 16cae8c1e5..33f7c61557 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -424,8 +424,9 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
if (added <= 0) {
_cleanup_free_ char *ip = NULL;
- in_addr_to_string(q->request_family, &q->request_address, &ip);
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
+ (void) in_addr_to_string(q->request_family, &q->request_address, &ip);
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR,
+ "Address '%s' does not have any RR of requested type", strnull(ip));
goto finish;
}
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 0af7551425..a54aed3a63 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -1734,7 +1734,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
if (r <= 0)
return r;
- wc = strjoina("*.", common_suffix, NULL);
+ wc = strjoina("*.", common_suffix);
return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
}
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index a5129c201e..081131ede0 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -262,7 +262,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
if (manager_our_packet(t->scope->manager, p) != 0)
return;
- in_addr_to_string(p->family, &p->sender, &pretty);
+ (void) in_addr_to_string(p->family, &p->sender, &pretty);
log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.",
t->id,
@@ -270,7 +270,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
af_to_name_short(t->scope->family),
- pretty);
+ strnull(pretty));
/* RFC 4795, Section 4.1 says that the peer with the
* lexicographically smaller IP address loses */
diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c
index c9b5ffa62b..b3018e8239 100644
--- a/src/resolve/test-dnssec.c
+++ b/src/resolve/test-dnssec.c
@@ -27,77 +27,89 @@
#include "string-util.h"
#include "hexdecoct.h"
-static void test_dnssec_verify_rrset2(void) {
+static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
+ char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
- static const uint8_t signature_blob[] = {
- 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
- 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
- 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
- 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
- 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
- 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
- 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
- 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
- };
+ assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
+ if (r < 0)
+ return;
+ assert_se(streq(canonicalized, canonical));
+}
+
+static void test_dnssec_canonicalize(void) {
+ test_dnssec_canonicalize_one("", ".", 1);
+ test_dnssec_canonicalize_one(".", ".", 1);
+ test_dnssec_canonicalize_one("foo", "foo.", 4);
+ test_dnssec_canonicalize_one("foo.", "foo.", 4);
+ test_dnssec_canonicalize_one("FOO.", "foo.", 4);
+ test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
+ test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
+}
+
+#ifdef HAVE_GCRYPT
+
+static void test_dnssec_verify_dns_key(void) {
+
+ static const uint8_t ds1_fprint[] = {
+ 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
+ 0x80, 0x67, 0x14, 0x01,
+ };
+ static const uint8_t ds2_fprint[] = {
+ 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
+ 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
+ };
static const uint8_t dnskey_blob[] = {
- 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
- 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
- 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
- 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
- 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
- 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
- 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
- 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
- 0x74, 0x62, 0xfe, 0xd7,
+ 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
+ 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
+ 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
+ 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
+ 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
+ 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
+ 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
+ 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
+ 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
+ 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
+ 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
+ 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
+ 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
+ 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
+ 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
+ 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
+ 0xe7, 0xea, 0x77, 0x03,
};
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- DnssecResult result;
-
- nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
- assert_se(nsec);
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
- nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
- assert_se(nsec->nsec.next_domain_name);
+ /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
+ ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
+ assert_se(ds1);
- nsec->nsec.types = bitmap_new();
- assert_se(nsec->nsec.types);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
+ ds1->ds.key_tag = 47857;
+ ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
+ ds1->ds.digest_size = sizeof(ds1_fprint);
+ ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
+ assert_se(ds1->ds.digest);
- log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
+ log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
- rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
- assert_se(rrsig);
+ ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
+ assert_se(ds2);
- rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
- rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- rrsig->rrsig.labels = 2;
- rrsig->rrsig.original_ttl = 300;
- rrsig->rrsig.expiration = 0x5689002f;
- rrsig->rrsig.inception = 0x56617230;
- rrsig->rrsig.key_tag = 30390;
- rrsig->rrsig.signer = strdup("Nasa.Gov.");
- assert_se(rrsig->rrsig.signer);
- rrsig->rrsig.signature_size = sizeof(signature_blob);
- rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
- assert_se(rrsig->rrsig.signature);
+ ds2->ds.key_tag = 47857;
+ ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
+ ds2->ds.digest_size = sizeof(ds2_fprint);
+ ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
+ assert_se(ds2->ds.digest);
- log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
+ log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
- dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
+ dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
assert_se(dnskey);
- dnskey->dnskey.flags = 256;
+ dnskey->dnskey.flags = 257;
dnskey->dnskey.protocol = 3;
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
dnskey->dnskey.key_size = sizeof(dnskey_blob);
@@ -107,16 +119,8 @@ static void test_dnssec_verify_rrset2(void) {
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
- assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
- assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
-
- answer = dns_answer_new(1);
- assert_se(answer);
- assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
-
- /* Validate the RR as it if was 2015-12-11 today */
- assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
- assert_se(result == DNSSEC_VALIDATED);
+ assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
+ assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
}
static void test_dnssec_verify_rrset(void) {
@@ -198,67 +202,77 @@ static void test_dnssec_verify_rrset(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_dns_key(void) {
+static void test_dnssec_verify_rrset2(void) {
- static const uint8_t ds1_fprint[] = {
- 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
- 0x80, 0x67, 0x14, 0x01,
- };
- static const uint8_t ds2_fprint[] = {
- 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
- 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
+ static const uint8_t signature_blob[] = {
+ 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
+ 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
+ 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
+ 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
+ 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
+ 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
+ 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
+ 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
};
+
static const uint8_t dnskey_blob[] = {
- 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
- 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
- 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
- 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
- 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
- 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
- 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
- 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
- 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
- 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
- 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
- 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
- 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
- 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
- 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
- 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
- 0xe7, 0xea, 0x77, 0x03,
+ 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
+ 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
+ 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
+ 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
+ 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
+ 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
+ 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
+ 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
+ 0x74, 0x62, 0xfe, 0xd7,
};
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
+ _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ DnssecResult result;
- /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
- ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
- assert_se(ds1);
+ nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
+ assert_se(nsec);
- ds1->ds.key_tag = 47857;
- ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
- ds1->ds.digest_size = sizeof(ds1_fprint);
- ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
- assert_se(ds1->ds.digest);
+ nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
+ assert_se(nsec->nsec.next_domain_name);
- log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
+ nsec->nsec.types = bitmap_new();
+ assert_se(nsec->nsec.types);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
- ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
- assert_se(ds2);
+ log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
- ds2->ds.key_tag = 47857;
- ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
- ds2->ds.digest_size = sizeof(ds2_fprint);
- ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
- assert_se(ds2->ds.digest);
+ rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
+ assert_se(rrsig);
- log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
+ rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
+ rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ rrsig->rrsig.labels = 2;
+ rrsig->rrsig.original_ttl = 300;
+ rrsig->rrsig.expiration = 0x5689002f;
+ rrsig->rrsig.inception = 0x56617230;
+ rrsig->rrsig.key_tag = 30390;
+ rrsig->rrsig.signer = strdup("Nasa.Gov.");
+ assert_se(rrsig->rrsig.signer);
+ rrsig->rrsig.signature_size = sizeof(signature_blob);
+ rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
+ assert_se(rrsig->rrsig.signature);
- dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
+ log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
+
+ dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
assert_se(dnskey);
- dnskey->dnskey.flags = 257;
+ dnskey->dnskey.flags = 256;
dnskey->dnskey.protocol = 3;
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
dnskey->dnskey.key_size = sizeof(dnskey_blob);
@@ -268,28 +282,16 @@ static void test_dnssec_verify_dns_key(void) {
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
- assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
- assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
-}
-
-static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
- char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
-
- assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
- if (r < 0)
- return;
+ assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
+ assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
- assert_se(streq(canonicalized, canonical));
-}
+ answer = dns_answer_new(1);
+ assert_se(answer);
+ assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
-static void test_dnssec_canonicalize(void) {
- test_dnssec_canonicalize_one("", ".", 1);
- test_dnssec_canonicalize_one(".", ".", 1);
- test_dnssec_canonicalize_one("foo", "foo.", 4);
- test_dnssec_canonicalize_one("foo.", "foo.", 4);
- test_dnssec_canonicalize_one("FOO.", "foo.", 4);
- test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
- test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
+ /* Validate the RR as it if was 2015-12-11 today */
+ assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
+ assert_se(result == DNSSEC_VALIDATED);
}
static void test_dnssec_nsec3_hash(void) {
@@ -324,9 +326,12 @@ static void test_dnssec_nsec3_hash(void) {
assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
}
+#endif
+
int main(int argc, char*argv[]) {
test_dnssec_canonicalize();
+
#ifdef HAVE_GCRYPT
test_dnssec_verify_dns_key();
test_dnssec_verify_rrset();
diff --git a/src/run/run.c b/src/run/run.c
index f92a7f4e2e..1993a424ca 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -103,7 +103,7 @@ static void help(void) {
" --uid=USER Run as system user\n"
" --gid=GROUP Run as system group\n"
" --nice=NICE Nice level\n"
- " --setenv=NAME=VALUE Set environment\n"
+ " -E --setenv=NAME=VALUE Set environment\n"
" -t --pty Run service on pseudo tty\n"
" -q --quiet Suppress information messages during runtime\n\n"
"Timer options:\n\n"
@@ -125,7 +125,6 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
- ARG_NO_ASK_PASSWORD,
ARG_USER,
ARG_SYSTEM,
ARG_SCOPE,
@@ -133,12 +132,10 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DESCRIPTION,
ARG_SLICE,
ARG_SEND_SIGHUP,
+ ARG_SERVICE_TYPE,
ARG_EXEC_USER,
ARG_EXEC_GROUP,
- ARG_SERVICE_TYPE,
ARG_NICE,
- ARG_SETENV,
- ARG_TTY,
ARG_ON_ACTIVE,
ARG_ON_BOOT,
ARG_ON_STARTUP,
@@ -147,6 +144,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ON_CALENDAR,
ARG_TIMER_PROPERTY,
ARG_NO_BLOCK,
+ ARG_NO_ASK_PASSWORD,
};
static const struct option options[] = {
@@ -166,9 +164,10 @@ static int parse_argv(int argc, char *argv[]) {
{ "uid", required_argument, NULL, ARG_EXEC_USER },
{ "gid", required_argument, NULL, ARG_EXEC_GROUP },
{ "nice", required_argument, NULL, ARG_NICE },
- { "setenv", required_argument, NULL, ARG_SETENV },
+ { "setenv", required_argument, NULL, 'E' },
{ "property", required_argument, NULL, 'p' },
- { "tty", no_argument, NULL, 't' },
+ { "tty", no_argument, NULL, 't' }, /* deprecated */
+ { "pty", no_argument, NULL, 't' },
{ "quiet", no_argument, NULL, 'q' },
{ "on-active", required_argument, NULL, ARG_ON_ACTIVE },
{ "on-boot", required_argument, NULL, ARG_ON_BOOT },
@@ -266,7 +265,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_nice_set = true;
break;
- case ARG_SETENV:
+ case 'E':
if (strv_extend(&arg_environment, optarg) < 0)
return log_oom();
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 0caaca03c7..6a1877d8aa 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -2050,8 +2050,8 @@ static void log_job_error_with_service_result(const char* service, const char *r
_cleanup_free_ char *t;
t = strv_join((char**) extra_args, " ");
- systemctl = strjoina("systemctl ", t ?: "<args>", NULL);
- journalctl = strjoina("journalctl ", t ?: "<args>", NULL);
+ systemctl = strjoina("systemctl ", t ? : "<args>");
+ journalctl = strjoina("journalctl ", t ? : "<args>");
}
if (!isempty(result)) {
@@ -2200,14 +2200,16 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
- if (!quiet) {
- if (streq(type, "symlink"))
- log_info("Created symlink from %s to %s.", path, source);
- else
- log_info("Removed symlink %s.", path);
+ /* We expect only "success" changes to be sent over the bus.
+ Hence, reject anything negative. */
+ UnitFileChangeType ch = unit_file_change_type_from_string(type);
+
+ if (ch < 0) {
+ log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
+ continue;
}
- r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
+ r = unit_file_changes_add(changes, n_changes, ch, path, source);
if (r < 0)
return r;
}
@@ -2218,6 +2220,7 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
if (r < 0)
return bus_log_parse_error(r);
+ unit_file_dump_changes(0, NULL, *changes, *n_changes, false);
return 0;
}
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index bd0a1f483b..1141f9964f 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -732,7 +732,7 @@ int config_parse_strv(const char *unit,
for (;;) {
char *word = NULL;
int r;
- r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+ r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
if (r == 0)
break;
if (r == -ENOMEM)
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index 0d3da2e6d2..ade2de7727 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -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>
diff --git a/src/shared/install.c b/src/shared/install.c
index ef8f485cae..71012eafb4 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -45,6 +45,7 @@
#include "mkdir.h"
#include "path-lookup.h"
#include "path-util.h"
+#include "rm-rf.h"
#include "set.h"
#include "special.h"
#include "stat-util.h"
@@ -65,7 +66,9 @@ typedef struct {
OrderedHashmap *have_processed;
} InstallContext;
-static int in_search_path(const char *path, char **search) {
+static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret);
+
+static int in_search_path(const LookupPaths *p, const char *path) {
_cleanup_free_ char *parent = NULL;
char **i;
@@ -75,141 +78,141 @@ static int in_search_path(const char *path, char **search) {
if (!parent)
return -ENOMEM;
- STRV_FOREACH(i, search)
+ STRV_FOREACH(i, p->search_path)
if (path_equal(parent, *i))
return true;
return false;
}
-static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
- char *p = NULL;
- int r;
+static const char* skip_root(const LookupPaths *p, const char *path) {
+ char *e;
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(ret);
-
- /* This determines where we shall create or remove our
- * installation ("configuration") symlinks */
+ assert(p);
+ assert(path);
- switch (scope) {
+ if (!p->root_dir)
+ return path;
- case UNIT_FILE_SYSTEM:
+ e = path_startswith(path, p->root_dir);
+ if (!e)
+ return NULL;
- if (runtime)
- p = path_join(root_dir, "/run/systemd/system", NULL);
- else
- p = path_join(root_dir, SYSTEM_CONFIG_UNIT_PATH, NULL);
- break;
+ /* Make sure the returned path starts with a slash */
+ if (e[0] != '/') {
+ if (e == path || e[-1] != '/')
+ return NULL;
- case UNIT_FILE_GLOBAL:
+ e--;
+ }
- if (root_dir)
- return -EINVAL;
+ return e;
+}
- if (runtime)
- p = strdup("/run/systemd/user");
- else
- p = strdup(USER_CONFIG_UNIT_PATH);
- break;
+static int path_is_generator(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
- case UNIT_FILE_USER:
+ assert(p);
+ assert(path);
- if (root_dir)
- return -EINVAL;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- if (runtime)
- r = user_runtime_dir(&p);
- else
- r = user_config_home(&p);
- if (r < 0)
- return r;
- if (r == 0)
- return -ENOENT;
+ return path_equal_ptr(parent, p->generator) ||
+ path_equal_ptr(parent, p->generator_early) ||
+ path_equal_ptr(parent, p->generator_late);
+}
- break;
+static int path_is_transient(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
- default:
- assert_not_reached("Bad scope");
- }
+ assert(p);
+ assert(path);
- if (!p)
+ parent = dirname_malloc(path);
+ if (!parent)
return -ENOMEM;
- *ret = p;
- return 0;
+ return path_equal_ptr(parent, p->transient);
}
-static bool is_config_path(UnitFileScope scope, const char *path) {
- int r;
+static int path_is_control(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(p);
assert(path);
- /* Checks whether the specified path is intended for
- * configuration or is outside of it */
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- switch (scope) {
+ return path_equal_ptr(parent, p->persistent_control) ||
+ path_equal_ptr(parent, p->runtime_control);
+}
- case UNIT_FILE_SYSTEM:
- case UNIT_FILE_GLOBAL:
- return path_startswith(path, "/etc") ||
- path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) ||
- path_startswith(path, "/run");
+static int path_is_config(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
+ assert(p);
+ assert(path);
- case UNIT_FILE_USER: {
- _cleanup_free_ char *p = NULL;
+ /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern
+ * configuration from transient or generated units */
- r = user_config_home(&p);
- if (r < 0)
- return r;
- if (r > 0 && path_startswith(path, p))
- return true;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- p = mfree(p);
+ return path_equal_ptr(parent, p->persistent_config) ||
+ path_equal_ptr(parent, p->runtime_config);
+}
- r = user_runtime_dir(&p);
- if (r < 0)
- return r;
- if (r > 0 && path_startswith(path, p))
- return true;
+static int path_is_runtime(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
+ const char *rpath;
- return false;
- }
+ assert(p);
+ assert(path);
- default:
- assert_not_reached("Bad scope");
- }
-}
+ /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime
+ * directories, as safety net. */
+ rpath = skip_root(p, path);
+ if (rpath && path_startswith(rpath, "/run"))
+ return true;
-static int verify_root_dir(UnitFileScope scope, const char **root_dir) {
- int r;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- assert(root_dir);
+ return path_equal_ptr(parent, p->runtime_config) ||
+ path_equal_ptr(parent, p->generator) ||
+ path_equal_ptr(parent, p->generator_early) ||
+ path_equal_ptr(parent, p->generator_late) ||
+ path_equal_ptr(parent, p->transient) ||
+ path_equal_ptr(parent, p->runtime_control);
+}
+
+static int path_is_vendor(const LookupPaths *p, const char *path) {
+ const char *rpath;
- /* Verifies that the specified root directory to operate on
- * makes sense. Reset it to NULL if it is the root directory
- * or set to empty */
+ assert(p);
+ assert(path);
- if (isempty(*root_dir) || path_equal(*root_dir, "/")) {
- *root_dir = NULL;
+ rpath = skip_root(p, path);
+ if (!rpath)
return 0;
- }
- if (scope != UNIT_FILE_SYSTEM)
- return -EINVAL;
+ if (path_startswith(rpath, "/usr"))
+ return true;
- r = is_dir(*root_dir, true);
- if (r < 0)
- return r;
- if (r == 0)
- return -ENOTDIR;
+#ifdef HAVE_SPLIT_USR
+ if (path_startswith(rpath, "/lib"))
+ return true;
+#endif
- return 0;
+ return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
}
int unit_file_changes_add(
@@ -273,6 +276,70 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
free(changes);
}
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet) {
+ unsigned i;
+ bool logged = false;
+
+ assert(changes || n_changes == 0);
+ /* If verb is not specified, errors are not allowed! */
+ assert(verb || r >= 0);
+
+ for (i = 0; i < n_changes; i++) {
+ assert(verb || changes[i].type >= 0);
+
+ switch(changes[i].type) {
+ case UNIT_FILE_SYMLINK:
+ if (!quiet)
+ log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
+ break;
+ case UNIT_FILE_UNLINK:
+ if (!quiet)
+ log_info("Removed %s.", changes[i].path);
+ break;
+ case UNIT_FILE_IS_MASKED:
+ if (!quiet)
+ log_info("Unit %s is masked, ignoring.", changes[i].path);
+ break;
+ case -EEXIST:
+ if (changes[i].source)
+ log_error_errno(changes[i].type,
+ "Failed to %s unit, file %s already exists and is a symlink to %s.",
+ verb, changes[i].path, changes[i].source);
+ else
+ log_error_errno(changes[i].type,
+ "Failed to %s unit, file %s already exists.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -ERFKILL:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -EADDRNOTAVAIL:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -ELOOP:
+ log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ default:
+ assert(changes[i].type < 0);
+ log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
+ verb, changes[i].path);
+ logged = true;
+ }
+ }
+
+ if (r < 0 && !logged)
+ log_error_errno(r, "Failed to %s: %m.", verb);
+}
+
+
+
static int create_symlink(
const char *old_path,
const char *new_path,
@@ -294,11 +361,13 @@ static int create_symlink(
if (symlink(old_path, new_path) >= 0) {
unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
- return 0;
+ return 1;
}
- if (errno != EEXIST)
+ if (errno != EEXIST) {
+ unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
return -errno;
+ }
r = readlink_malloc(new_path, &dest);
if (r < 0)
@@ -307,8 +376,10 @@ static int create_symlink(
if (path_equal(dest, old_path))
return 0;
- if (!force)
+ if (!force) {
+ unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
return -EEXIST;
+ }
r = symlink_atomic(old_path, new_path);
if (r < 0)
@@ -317,7 +388,7 @@ static int create_symlink(
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
- return 0;
+ return 1;
}
static int mark_symlink_for_removal(
@@ -353,6 +424,7 @@ static int remove_marked_symlinks_fd(
int fd,
const char *path,
const char *config_path,
+ const LookupPaths *lp,
bool *restart,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -365,6 +437,7 @@ static int remove_marked_symlinks_fd(
assert(fd >= 0);
assert(path);
assert(config_path);
+ assert(lp);
assert(restart);
d = fdopendir(fd);
@@ -400,12 +473,13 @@ static int remove_marked_symlinks_fd(
}
/* This will close nfd, regardless whether it succeeds or not */
- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes);
+ q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes);
if (q < 0 && r == 0)
r = q;
} else if (de->d_type == DT_LNK) {
_cleanup_free_ char *p = NULL, *dest = NULL;
+ const char *rp;
bool found;
int q;
@@ -415,42 +489,43 @@ static int remove_marked_symlinks_fd(
p = path_make_absolute(de->d_name, path);
if (!p)
return -ENOMEM;
+ path_kill_slashes(p);
q = readlink_malloc(p, &dest);
+ if (q == -ENOENT)
+ continue;
if (q < 0) {
- if (q == -ENOENT)
- continue;
-
if (r == 0)
r = q;
continue;
}
- /* We remove all links pointing to a file or
- * path that is marked, as well as all files
- * sharing the same name as a file that is
- * marked. */
+ /* We remove all links pointing to a file or path that is marked, as well as all files sharing
+ * the same name as a file that is marked. */
- found =
- set_contains(remove_symlinks_to, dest) ||
+ found = set_contains(remove_symlinks_to, dest) ||
set_contains(remove_symlinks_to, basename(dest)) ||
set_contains(remove_symlinks_to, de->d_name);
if (!found)
continue;
- if (unlink(p) < 0 && errno != ENOENT) {
+ if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
if (r == 0)
r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, p, NULL);
continue;
}
- path_kill_slashes(p);
(void) rmdir_parents(p, config_path);
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
- q = mark_symlink_for_removal(&remove_symlinks_to, p);
+ /* Now, remember the full path (but with the root prefix removed) of the symlink we just
+ * removed, and remove any symlinks to it, too */
+
+ rp = skip_root(lp, p);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
if (q < 0)
return q;
if (q > 0)
@@ -464,6 +539,7 @@ static int remove_marked_symlinks_fd(
static int remove_marked_symlinks(
Set *remove_symlinks_to,
const char *config_path,
+ const LookupPaths *lp,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -472,6 +548,7 @@ static int remove_marked_symlinks(
int r = 0;
assert(config_path);
+ assert(lp);
if (set_size(remove_symlinks_to) <= 0)
return 0;
@@ -489,7 +566,7 @@ static int remove_marked_symlinks(
return -errno;
/* This takes possession of cfd and closes it */
- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes);
+ q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes);
if (r == 0)
r = q;
} while (restart);
@@ -503,6 +580,7 @@ static int find_symlinks_fd(
int fd,
const char *path,
const char *config_path,
+ const LookupPaths *lp,
bool *same_name_link) {
_cleanup_closedir_ DIR *d = NULL;
@@ -513,6 +591,7 @@ static int find_symlinks_fd(
assert(fd >= 0);
assert(path);
assert(config_path);
+ assert(lp);
assert(same_name_link);
d = fdopendir(fd);
@@ -546,7 +625,7 @@ static int find_symlinks_fd(
}
/* This will close nfd, regardless whether it succeeds or not */
- q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link);
+ q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link);
if (q > 0)
return 1;
if (r == 0)
@@ -624,6 +703,7 @@ static int find_symlinks(
const char *root_dir,
const char *name,
const char *config_path,
+ const LookupPaths *lp,
bool *same_name_link) {
int fd;
@@ -640,29 +720,25 @@ static int find_symlinks(
}
/* This takes possession of fd and closes it */
- return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link);
+ return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link);
}
static int find_symlinks_in_scope(
UnitFileScope scope,
- const char *root_dir,
+ const LookupPaths *paths,
const char *name,
UnitFileState *state) {
- _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL;
bool same_name_link_runtime = false, same_name_link = false;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(paths);
assert(name);
- /* First look in the normal config path */
- r = get_config_path(scope, false, root_dir, &normal_path);
- if (r < 0)
- return r;
-
- r = find_symlinks(root_dir, name, normal_path, &same_name_link);
+ /* First look in the persistent config path */
+ r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link);
if (r < 0)
return r;
if (r > 0) {
@@ -671,11 +747,7 @@ static int find_symlinks_in_scope(
}
/* Then look in runtime config path */
- r = get_config_path(scope, true, root_dir, &runtime_path);
- if (r < 0)
- return r;
-
- r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime);
+ r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime);
if (r < 0)
return r;
if (r > 0) {
@@ -742,6 +814,30 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam
return ordered_hashmap_get(c->will_process, name);
}
+static int install_info_may_process(
+ UnitFileInstallInfo *i,
+ const LookupPaths *paths,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
+ assert(i);
+ assert(paths);
+
+ /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
+ * not subject to enable/disable operations. */
+
+ if (i->type == UNIT_FILE_TYPE_MASKED) {
+ unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
+ return -ERFKILL;
+ }
+ if (path_is_generator(paths, i->path) ||
+ path_is_transient(paths, i->path)) {
+ unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
static int install_info_add(
InstallContext *c,
const char *name,
@@ -804,20 +900,6 @@ fail:
return r;
}
-static int install_info_add_auto(
- InstallContext *c,
- const char *name_or_path,
- UnitFileInstallInfo **ret) {
-
- assert(c);
- assert(name_or_path);
-
- if (path_is_absolute(name_or_path))
- return install_info_add(c, NULL, name_or_path, ret);
- else
- return install_info_add(c, name_or_path, NULL, ret);
-}
-
static int config_parse_also(
const char *unit,
const char *filename,
@@ -900,7 +982,6 @@ static int unit_file_load(
InstallContext *c,
UnitFileInstallInfo *info,
const char *path,
- const char *root_dir,
SearchFlags flags) {
const ConfigTableItem items[] = {
@@ -921,8 +1002,6 @@ static int unit_file_load(
assert(info);
assert(path);
- path = prefix_roota(root_dir, path);
-
if (!(flags & SEARCH_LOAD)) {
r = lstat(path, &st);
if (r < 0)
@@ -983,26 +1062,26 @@ static int unit_file_load_or_readlink(
const char *root_dir,
SearchFlags flags) {
- _cleanup_free_ char *np = NULL;
+ _cleanup_free_ char *target = NULL;
int r;
- r = unit_file_load(c, info, path, root_dir, flags);
+ r = unit_file_load(c, info, path, flags);
if (r != -ELOOP)
return r;
/* This is a symlink, let's read it. */
- r = readlink_and_make_absolute_root(root_dir, path, &np);
+ r = readlink_malloc(path, &target);
if (r < 0)
return r;
- if (path_equal(np, "/dev/null"))
+ if (path_equal(target, "/dev/null"))
info->type = UNIT_FILE_TYPE_MASKED;
else {
const char *bn;
UnitType a, b;
- bn = basename(np);
+ bn = basename(target);
if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
@@ -1029,9 +1108,16 @@ static int unit_file_load_or_readlink(
if (a < 0 || b < 0 || a != b)
return -EINVAL;
+ if (path_is_absolute(target))
+ /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
+ info->symlink_target = prefix_root(root_dir, target);
+ else
+ /* This is a relative path, take it relative to the dir the symlink is located in. */
+ info->symlink_target = file_in_same_dir(path, target);
+ if (!info->symlink_target)
+ return -ENOMEM;
+
info->type = UNIT_FILE_TYPE_SYMLINK;
- info->symlink_target = np;
- np = NULL;
}
return 0;
@@ -1041,7 +1127,6 @@ static int unit_file_search(
InstallContext *c,
UnitFileInstallInfo *info,
const LookupPaths *paths,
- const char *root_dir,
SearchFlags flags) {
char **p;
@@ -1056,18 +1141,18 @@ static int unit_file_search(
return 0;
if (info->path)
- return unit_file_load_or_readlink(c, info, info->path, root_dir, flags);
+ return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
assert(info->name);
- STRV_FOREACH(p, paths->unit_path) {
+ STRV_FOREACH(p, paths->search_path) {
_cleanup_free_ char *path = NULL;
path = strjoin(*p, "/", info->name, NULL);
if (!path)
return -ENOMEM;
- r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
+ r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
if (r < 0) {
if (r != -ENOENT)
return r;
@@ -1090,14 +1175,14 @@ static int unit_file_search(
if (r < 0)
return r;
- STRV_FOREACH(p, paths->unit_path) {
+ STRV_FOREACH(p, paths->search_path) {
_cleanup_free_ char *path = NULL;
path = strjoin(*p, "/", template, NULL);
if (!path)
return -ENOMEM;
- r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
+ r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
if (r < 0) {
if (r != -ENOENT)
return r;
@@ -1143,7 +1228,6 @@ static int install_info_follow(
static int install_info_traverse(
UnitFileScope scope,
InstallContext *c,
- const char *root_dir,
const LookupPaths *paths,
UnitFileInstallInfo *start,
SearchFlags flags,
@@ -1157,7 +1241,7 @@ static int install_info_traverse(
assert(start);
assert(c);
- r = unit_file_search(c, start, paths, root_dir, flags);
+ r = unit_file_search(c, start, paths, flags);
if (r < 0)
return r;
@@ -1168,10 +1252,15 @@ static int install_info_traverse(
if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
return -ELOOP;
- if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path))
- return -ELOOP;
+ if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
+ r = path_is_config(paths, i->path);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return -ELOOP;
+ }
- r = install_info_follow(c, i, root_dir, flags);
+ r = install_info_follow(c, i, paths->root_dir, flags);
if (r < 0) {
_cleanup_free_ char *buffer = NULL;
const char *bn;
@@ -1205,7 +1294,7 @@ static int install_info_traverse(
if (r < 0)
return r;
- r = unit_file_search(c, i, paths, root_dir, flags);
+ r = unit_file_search(c, i, paths, flags);
if (r < 0)
return r;
}
@@ -1219,10 +1308,28 @@ static int install_info_traverse(
return 0;
}
+static int install_info_add_auto(
+ InstallContext *c,
+ const LookupPaths *paths,
+ const char *name_or_path,
+ UnitFileInstallInfo **ret) {
+
+ assert(c);
+ assert(name_or_path);
+
+ if (path_is_absolute(name_or_path)) {
+ const char *pp;
+
+ pp = prefix_roota(paths->root_dir, name_or_path);
+
+ return install_info_add(c, NULL, pp, ret);
+ } else
+ return install_info_add(c, name_or_path, NULL, ret);
+}
+
static int install_info_discover(
UnitFileScope scope,
InstallContext *c,
- const char *root_dir,
const LookupPaths *paths,
const char *name,
SearchFlags flags,
@@ -1235,15 +1342,16 @@ static int install_info_discover(
assert(paths);
assert(name);
- r = install_info_add_auto(c, name, &i);
+ r = install_info_add_auto(c, paths, name, &i);
if (r < 0)
return r;
- return install_info_traverse(scope, c, root_dir, paths, i, flags, ret);
+ return install_info_traverse(scope, c, paths, i, flags, ret);
}
static int install_info_symlink_alias(
UnitFileInstallInfo *i,
+ const LookupPaths *paths,
const char *config_path,
bool force,
UnitFileChange **changes,
@@ -1253,10 +1361,12 @@ static int install_info_symlink_alias(
int r = 0, q;
assert(i);
+ assert(paths);
assert(config_path);
STRV_FOREACH(s, i->aliases) {
_cleanup_free_ char *alias_path = NULL, *dst = NULL;
+ const char *rp;
q = install_full_printf(i, *s, &dst);
if (q < 0)
@@ -1266,7 +1376,9 @@ static int install_info_symlink_alias(
if (!alias_path)
return -ENOMEM;
- q = create_symlink(i->path, alias_path, force, changes, n_changes);
+ rp = skip_root(paths, i->path);
+
+ q = create_symlink(rp ?: i->path, alias_path, force, changes, n_changes);
if (r == 0)
r = q;
}
@@ -1276,6 +1388,7 @@ static int install_info_symlink_alias(
static int install_info_symlink_wants(
UnitFileInstallInfo *i,
+ const LookupPaths *paths,
const char *config_path,
char **list,
const char *suffix,
@@ -1289,6 +1402,7 @@ static int install_info_symlink_wants(
int r = 0, q;
assert(i);
+ assert(paths);
assert(config_path);
if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
@@ -1309,6 +1423,7 @@ static int install_info_symlink_wants(
STRV_FOREACH(s, list) {
_cleanup_free_ char *path = NULL, *dst = NULL;
+ const char *rp;
q = install_full_printf(i, *s, &dst);
if (q < 0)
@@ -1323,7 +1438,9 @@ static int install_info_symlink_wants(
if (!path)
return -ENOMEM;
- q = create_symlink(i->path, path, force, changes, n_changes);
+ rp = skip_root(paths, i->path);
+
+ q = create_symlink(rp ?: i->path, path, force, changes, n_changes);
if (r == 0)
r = q;
}
@@ -1335,12 +1452,12 @@ static int install_info_symlink_link(
UnitFileInstallInfo *i,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
_cleanup_free_ char *path = NULL;
+ const char *rp;
int r;
assert(i);
@@ -1348,22 +1465,25 @@ static int install_info_symlink_link(
assert(config_path);
assert(i->path);
- r = in_search_path(i->path, paths->unit_path);
- if (r != 0)
+ r = in_search_path(paths, i->path);
+ if (r < 0)
return r;
+ if (r > 0)
+ return 0;
path = strjoin(config_path, "/", i->name, NULL);
if (!path)
return -ENOMEM;
- return create_symlink(i->path, path, force, changes, n_changes);
+ rp = skip_root(paths, i->path);
+
+ return create_symlink(rp ?: i->path, path, force, changes, n_changes);
}
static int install_info_apply(
UnitFileInstallInfo *i,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -1377,18 +1497,19 @@ static int install_info_apply(
if (i->type != UNIT_FILE_TYPE_REGULAR)
return 0;
- r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
+ r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
- q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
+ q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
if (r == 0)
r = q;
- q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes);
+ q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", force, changes, n_changes);
if (r == 0)
r = q;
- q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes);
- if (r == 0)
+ q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
+ /* Do not count links to the unit file towards the "carries_install_info" count */
+ if (r == 0 && q < 0)
r = q;
return r;
@@ -1399,7 +1520,6 @@ static int install_context_apply(
InstallContext *c,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
bool force,
SearchFlags flags,
UnitFileChange **changes,
@@ -1427,19 +1547,19 @@ static int install_context_apply(
if (q < 0)
return q;
- r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL);
+ r = install_info_traverse(scope, c, paths, i, flags, NULL);
if (r < 0)
return r;
if (i->type != UNIT_FILE_TYPE_REGULAR)
continue;
- q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
+ q = install_info_apply(i, paths, config_path, force, changes, n_changes);
if (r >= 0) {
if (q < 0)
r = q;
else
- r+= q;
+ r += q;
}
}
@@ -1451,8 +1571,7 @@ static int install_context_mark_for_removal(
InstallContext *c,
const LookupPaths *paths,
Set **remove_symlinks_to,
- const char *config_path,
- const char *root_dir) {
+ const char *config_path) {
UnitFileInstallInfo *i;
int r;
@@ -1476,7 +1595,7 @@ static int install_context_mark_for_removal(
if (r < 0)
return r;
- r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
+ r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
if (r < 0)
return r;
@@ -1500,20 +1619,19 @@ int unit_file_mask(
UnitFileChange **changes,
unsigned *n_changes) {
- _cleanup_free_ char *prefix = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ const char *config_path;
char **i;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &prefix);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
@@ -1525,7 +1643,7 @@ int unit_file_mask(
continue;
}
- path = path_make_absolute(*i, prefix);
+ path = path_make_absolute(*i, config_path);
if (!path)
return -ENOMEM;
@@ -1545,23 +1663,22 @@ int unit_file_unmask(
UnitFileChange **changes,
unsigned *n_changes) {
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- _cleanup_free_ char *config_path = NULL;
_cleanup_free_ char **todo = NULL;
size_t n_todo = 0, n_allocated = 0;
+ const char *config_path;
char **i;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
@@ -1592,24 +1709,31 @@ int unit_file_unmask(
r = 0;
STRV_FOREACH(i, todo) {
_cleanup_free_ char *path = NULL;
+ const char *rp;
path = path_make_absolute(*i, config_path);
if (!path)
return -ENOMEM;
if (unlink(path) < 0) {
- if (errno != -ENOENT && r >= 0)
- r = -errno;
- } else {
- q = mark_symlink_for_removal(&remove_symlinks_to, path);
- if (q < 0)
- return q;
+ if (errno != ENOENT) {
+ if (r >= 0)
+ r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, path, NULL);
+ }
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ continue;
}
+
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+
+ rp = skip_root(&paths, path);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
+ if (q < 0)
+ return q;
}
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
if (r >= 0)
r = q;
@@ -1626,26 +1750,20 @@ int unit_file_link(
unsigned *n_changes) {
_cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
_cleanup_free_ char **todo = NULL;
size_t n_todo = 0, n_allocated = 0;
+ const char *config_path;
char **i;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
_cleanup_free_ char *full = NULL;
@@ -1659,7 +1777,7 @@ int unit_file_link(
if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
return -EINVAL;
- full = prefix_root(root_dir, *i);
+ full = prefix_root(paths.root_dir, *i);
if (!full)
return -ENOMEM;
@@ -1672,7 +1790,7 @@ int unit_file_link(
if (!S_ISREG(st.st_mode))
return -ENOTTY;
- q = in_search_path(*i, paths.unit_path);
+ q = in_search_path(&paths, *i);
if (q < 0)
return q;
if (q > 0)
@@ -1688,13 +1806,15 @@ int unit_file_link(
r = 0;
STRV_FOREACH(i, todo) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *new_path = NULL;
+ const char *old_path;
- path = path_make_absolute(basename(*i), config_path);
- if (!path)
+ old_path = skip_root(&paths, *i);
+ new_path = path_make_absolute(basename(*i), config_path);
+ if (!new_path)
return -ENOMEM;
- q = create_symlink(*i, path, force, changes, n_changes);
+ q = create_symlink(old_path ?: *i, new_path, force, changes, n_changes);
if (q < 0 && r >= 0)
r = q;
}
@@ -1702,6 +1822,182 @@ int unit_file_link(
return r;
}
+static int path_shall_revert(const LookupPaths *paths, const char *path) {
+ int r;
+
+ assert(paths);
+ assert(path);
+
+ /* Checks whether the path is one where the drop-in directories shall be removed. */
+
+ r = path_is_config(paths, path);
+ if (r != 0)
+ return r;
+
+ r = path_is_control(paths, path);
+ if (r != 0)
+ return r;
+
+ return path_is_transient(paths, path);
+}
+
+int unit_file_revert(
+ UnitFileScope scope,
+ const char *root_dir,
+ char **files,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
+
+ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+ /* _cleanup_(install_context_done) InstallContext c = {}; */
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_strv_free_ char **todo = NULL;
+ size_t n_todo = 0, n_allocated = 0;
+ char **i;
+ int r, q;
+
+ /* Puts a unit file back into vendor state. This means:
+ *
+ * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
+ * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
+ *
+ * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
+ * "config", but not in "transient" or "control" or even "generated").
+ *
+ * We remove all that in both the runtime and the persistant directories, if that applies.
+ */
+
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(i, files) {
+ bool has_vendor = false;
+ char **p;
+
+ if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ STRV_FOREACH(p, paths.search_path) {
+ _cleanup_free_ char *path = NULL, *dropin = NULL;
+ struct stat st;
+
+ path = path_make_absolute(*i, *p);
+ if (!path)
+ return -ENOMEM;
+
+ r = lstat(path, &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ } else if (S_ISREG(st.st_mode)) {
+ /* Check if there's a vendor version */
+ r = path_is_vendor(&paths, path);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ has_vendor = true;
+ }
+
+ dropin = strappend(path, ".d");
+ if (!dropin)
+ return -ENOMEM;
+
+ r = lstat(dropin, &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ } else if (S_ISDIR(st.st_mode)) {
+ /* Remove the drop-ins */
+ r = path_shall_revert(&paths, dropin);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+ return -ENOMEM;
+
+ todo[n_todo++] = dropin;
+ dropin = NULL;
+ }
+ }
+ }
+
+ if (!has_vendor)
+ continue;
+
+ /* OK, there's a vendor version, hence drop all configuration versions */
+ STRV_FOREACH(p, paths.search_path) {
+ _cleanup_free_ char *path = NULL;
+ struct stat st;
+
+ path = path_make_absolute(*i, *p);
+ if (!path)
+ return -ENOMEM;
+
+ r = lstat(path, &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+ r = path_is_config(&paths, path);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+ return -ENOMEM;
+
+ todo[n_todo++] = path;
+ path = NULL;
+ }
+ }
+ }
+ }
+
+ strv_uniq(todo);
+
+ r = 0;
+ STRV_FOREACH(i, todo) {
+ _cleanup_strv_free_ char **fs = NULL;
+ const char *rp;
+ char **j;
+
+ (void) get_files_in_directory(*i, &fs);
+
+ q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
+ if (q < 0 && q != -ENOENT && r >= 0) {
+ r = q;
+ continue;
+ }
+
+ STRV_FOREACH(j, fs) {
+ _cleanup_free_ char *t = NULL;
+
+ t = strjoin(*i, "/", *j, NULL);
+ if (!t)
+ return -ENOMEM;
+
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
+ }
+
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
+
+ rp = skip_root(&paths, *i);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
+ if (q < 0)
+ return q;
+ }
+
+ q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes);
+ if (r >= 0)
+ r = q;
+
+ q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes);
+ if (r >= 0)
+ r = q;
+
+ return r;
+}
+
int unit_file_add_dependency(
UnitFileScope scope,
bool runtime,
@@ -1715,8 +2011,8 @@ int unit_file_add_dependency(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
UnitFileInstallInfo *i, *target_info;
+ const char *config_path;
char **f;
int r;
@@ -1730,34 +2026,30 @@ int unit_file_add_dependency(
if (!unit_name_is_valid(target, UNIT_NAME_ANY))
return -EINVAL;
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
- r = get_config_path(scope, runtime, root_dir, &config_path);
+ r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
if (r < 0)
return r;
-
- r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
+ r = install_info_may_process(target_info, &paths, changes, n_changes);
if (r < 0)
return r;
- if (target_info->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
STRV_FOREACH(f, files) {
char ***l;
- r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ if (r < 0)
+ return r;
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
assert(i->type == UNIT_FILE_TYPE_REGULAR);
@@ -1776,7 +2068,7 @@ int unit_file_add_dependency(
return -ENOMEM;
}
- return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
+ return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
}
int unit_file_enable(
@@ -1790,7 +2082,7 @@ int unit_file_enable(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
+ const char *config_path;
UnitFileInstallInfo *i;
char **f;
int r;
@@ -1798,24 +2090,19 @@ int unit_file_enable(
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(f, files) {
- r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i);
+ r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i);
+ if (r < 0)
+ return r;
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
assert(i->type == UNIT_FILE_TYPE_REGULAR);
}
@@ -1825,7 +2112,7 @@ int unit_file_enable(
is useful to determine whether the passed files had any
installation data at all. */
- return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
+ return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes);
}
int unit_file_disable(
@@ -1838,25 +2125,19 @@ int unit_file_disable(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+ const char *config_path;
char **i;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
@@ -1867,11 +2148,11 @@ int unit_file_disable(
return r;
}
- r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir);
+ r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path);
if (r < 0)
return r;
- return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
}
int unit_file_reenable(
@@ -1912,41 +2193,34 @@ int unit_file_set_default(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
UnitFileInstallInfo *i;
- const char *path;
+ const char *new_path, *old_path;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- if (unit_name_to_type(name) != UNIT_TARGET)
+ if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
return -EINVAL;
if (streq(name, SPECIAL_DEFAULT_TARGET))
return -EINVAL;
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, false, root_dir, &config_path);
+ r = install_info_discover(scope, &c, &paths, name, 0, &i);
if (r < 0)
return r;
-
- r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i);
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
- path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
+ old_path = skip_root(&paths, i->path);
+ new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
- return create_symlink(i->path, path, force, changes, n_changes);
+ return create_symlink(old_path ?: i->path, new_path, force, changes, n_changes);
}
int unit_file_get_default(
@@ -1964,19 +2238,16 @@ int unit_file_get_default(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
-
- r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_may_process(i, &paths, NULL, 0);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
n = strdup(i->name);
if (!n)
@@ -1986,9 +2257,8 @@ int unit_file_get_default(
return 0;
}
-int unit_file_lookup_state(
+static int unit_file_lookup_state(
UnitFileScope scope,
- const char *root_dir,
const LookupPaths *paths,
const char *name,
UnitFileState *ret) {
@@ -2004,11 +2274,7 @@ int unit_file_lookup_state(
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
@@ -2019,11 +2285,31 @@ int unit_file_lookup_state(
switch (i->type) {
case UNIT_FILE_TYPE_MASKED:
- state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+ r = path_is_runtime(paths, i->path);
+ if (r < 0)
+ return r;
+
+ state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
break;
case UNIT_FILE_TYPE_REGULAR:
- r = find_symlinks_in_scope(scope, root_dir, i->name, &state);
+ r = path_is_generator(paths, i->path);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ state = UNIT_FILE_GENERATED;
+ break;
+ }
+
+ r = path_is_transient(paths, i->path);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ state = UNIT_FILE_TRANSIENT;
+ break;
+ }
+
+ r = find_symlinks_in_scope(scope, paths, i->name, &state);
if (r < 0)
return r;
if (r == 0) {
@@ -2058,15 +2344,30 @@ int unit_file_get_state(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ return unit_file_lookup_state(scope, &paths, name, ret);
+}
+
+int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
+ _cleanup_(install_context_done) InstallContext c = {};
+ int r;
+
+ assert(paths);
+ assert(name);
+
+ if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ r = install_info_discover(scope, &c, paths, name, 0, NULL);
+ if (r == -ENOENT)
+ return 0;
if (r < 0)
return r;
- return unit_file_lookup_state(scope, root_dir, &paths, name, ret);
+ return 1;
}
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
@@ -2078,10 +2379,6 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
@@ -2164,7 +2461,6 @@ static int execute_preset(
InstallContext *minus,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
char **files,
UnitFilePresetMode mode,
bool force,
@@ -2181,11 +2477,11 @@ static int execute_preset(
if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir);
+ r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
if (r < 0)
return r;
- r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes);
} else
r = 0;
@@ -2193,12 +2489,12 @@ static int execute_preset(
int q;
/* Returns number of symlinks that where supposed to be installed. */
- q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
+ q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
if (r >= 0) {
if (q < 0)
r = q;
else
- r+= q;
+ r += q;
}
}
@@ -2210,9 +2506,10 @@ static int preset_prepare_one(
InstallContext *plus,
InstallContext *minus,
LookupPaths *paths,
- const char *root_dir,
UnitFilePresetMode mode,
- const char *name) {
+ const char *name,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
UnitFileInstallInfo *i;
int r;
@@ -2221,19 +2518,20 @@ static int preset_prepare_one(
install_info_find(minus, name))
return 0;
- r = unit_file_query_preset(scope, root_dir, name);
+ r = unit_file_query_preset(scope, paths->root_dir, name);
if (r < 0)
return r;
if (r > 0) {
- r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
+ r = install_info_may_process(i, paths, changes, n_changes);
+ if (r < 0)
+ return r;
} else
- r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
return r;
}
@@ -2250,7 +2548,7 @@ int unit_file_preset(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
+ const char *config_path;
char **i;
int r;
@@ -2258,28 +2556,22 @@ int unit_file_preset(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(mode < _UNIT_FILE_PRESET_MAX);
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
return -EINVAL;
- r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i);
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes);
if (r < 0)
return r;
}
- return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes);
+ return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes);
}
int unit_file_preset_all(
@@ -2293,7 +2585,7 @@ int unit_file_preset_all(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
+ const char *config_path = NULL;
char **i;
int r;
@@ -2301,28 +2593,17 @@ int unit_file_preset_all(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(mode < _UNIT_FILE_PRESET_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
- STRV_FOREACH(i, paths.unit_path) {
+ STRV_FOREACH(i, paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *units_dir;
struct dirent *de;
- units_dir = path_join(root_dir, *i, NULL);
- if (!units_dir)
- return -ENOMEM;
-
- d = opendir(units_dir);
+ d = opendir(*i);
if (!d) {
if (errno == ENOENT)
continue;
@@ -2340,13 +2621,17 @@ int unit_file_preset_all(
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
- r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name);
+ /* we don't pass changes[] in, because we want to handle errors on our own */
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, NULL, 0);
+ if (r == -ERFKILL)
+ r = unit_file_changes_add(changes, n_changes,
+ UNIT_FILE_IS_MASKED, de->d_name, NULL);
if (r < 0)
return r;
}
}
- return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes);
+ return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes);
}
static void unit_file_list_free_one(UnitFileList *f) {
@@ -2381,24 +2666,15 @@ int unit_file_get_list(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(h);
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- STRV_FOREACH(i, paths.unit_path) {
+ STRV_FOREACH(i, paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *units_dir;
struct dirent *de;
- units_dir = path_join(root_dir, *i, NULL);
- if (!units_dir)
- return -ENOMEM;
-
- d = opendir(units_dir);
+ d = opendir(*i);
if (!d) {
if (errno == ENOENT)
continue;
@@ -2424,11 +2700,11 @@ int unit_file_get_list(
if (!f)
return -ENOMEM;
- f->path = path_make_absolute(de->d_name, units_dir);
+ f->path = path_make_absolute(de->d_name, *i);
if (!f->path)
return -ENOMEM;
- r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state);
+ r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
if (r < 0)
f->state = UNIT_FILE_BAD;
@@ -2453,6 +2729,8 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
[UNIT_FILE_STATIC] = "static",
[UNIT_FILE_DISABLED] = "disabled",
[UNIT_FILE_INDIRECT] = "indirect",
+ [UNIT_FILE_GENERATED] = "generated",
+ [UNIT_FILE_TRANSIENT] = "transient",
[UNIT_FILE_BAD] = "bad",
};
@@ -2461,6 +2739,7 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
[UNIT_FILE_SYMLINK] = "symlink",
[UNIT_FILE_UNLINK] = "unlink",
+ [UNIT_FILE_IS_MASKED] = "masked",
};
DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
diff --git a/src/shared/install.h b/src/shared/install.h
index c1a43e23e7..4133faffa2 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -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
@@ -70,16 +72,29 @@ enum UnitFilePresetMode {
enum UnitFileChangeType {
UNIT_FILE_SYMLINK,
UNIT_FILE_UNLINK,
+ UNIT_FILE_IS_MASKED,
_UNIT_FILE_CHANGE_TYPE_MAX,
- _UNIT_FILE_CHANGE_TYPE_INVALID = -1
+ _UNIT_FILE_CHANGE_INVALID = INT_MIN
};
+/* type can either one of the UnitFileChangeTypes listed above, or a negative error.
+ * If source is specified, it should be the contents of the path symlink.
+ * In case of an error, source should be the existing symlink contents or NULL
+ */
struct UnitFileChange {
- UnitFileChangeType type;
+ int type; /* UnitFileChangeType or bust */
char *path;
char *source;
};
+static inline bool unit_file_changes_have_modification(const UnitFileChange* changes, unsigned n_changes) {
+ unsigned i;
+ for (i = 0; i < n_changes; i++)
+ if (IN_SET(changes[i].type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK))
+ return true;
+ return false;
+}
+
struct UnitFileList {
char *path;
UnitFileState state;
@@ -123,31 +138,112 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
return !strv_isempty(i->also);
}
-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_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_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_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_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);
int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source);
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet);
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
const char *unit_file_state_to_string(UnitFileState s) _const_;
UnitFileState unit_file_state_from_string(const char *s) _pure_;
+/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_;
UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_;
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index d2f1c4a40c..bebfc40efe 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -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)
diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h
index 31b720d50c..7410168c4f 100644
--- a/src/shared/machine-image.h
+++ b/src/shared/machine-image.h
@@ -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;
+}
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index 5410620725..80a2ea7940 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -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;
- e = getenv("XDG_CONFIG_HOME");
- if (e) {
- r = strappend(e, "/systemd/user");
- if (!r)
- return -ENOMEM;
-
- *config_home = r;
- return 1;
- } else {
- const char *home;
+ assert(ret);
+ assert(suffix);
- home = getenv("HOME");
- if (home) {
- r = strappend(home, "/.config/systemd/user");
- if (!r)
- return -ENOMEM;
+ e = getenv("XDG_RUNTIME_DIR");
+ if (!e)
+ return -ENXIO;
- *config_home = r;
- return 1;
- }
- }
+ j = strappend(e, suffix);
+ if (!j)
+ return -ENOMEM;
+ *ret = j;
return 0;
}
-int user_runtime_dir(char **runtime_dir) {
+static int user_config_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;
+ assert(ret);
+
+ e = getenv("XDG_CONFIG_HOME");
+ if (e)
+ j = strappend(e, suffix);
+ else {
+ const char *home;
- *runtime_dir = r;
- return 1;
+ home = getenv("HOME");
+ if (!home)
+ return -ENXIO;
+
+ j = strjoin(home, "/.config", suffix, NULL);
}
+ if (!j)
+ return -ENOMEM;
+
+ *ret = j;
return 0;
}
-static int user_data_home_dir(char **dir, const char *suffix) {
+static int user_data_dir(char **ret, const char *suffix) {
const char *e;
- char *res;
+ char *j;
+
+ 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_strv(&res, (char**) config_unit_paths, false) < 0)
+ if (strv_extend(&res, persistent_config) < 0)
return NULL;
- if (runtime_dir)
- if (strv_extend(&res, runtime_dir) < 0)
- return NULL;
+ if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 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,298 @@ 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/");
+ 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) {
-
- const char *e;
+ UnitFileScope scope,
+ LookupPathsFlags flags,
+ const char *root_dir) {
+
+ _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 */
+ _cleanup_strv_free_ char **paths = NULL;
+ const char *e;
int r;
assert(p);
+ assert(scope >= 0);
+ assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+ 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 */
+ /* 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, &paths);
if (r < 0)
return r;
- } else
- p->unit_path = NULL;
+ }
- if (!p->unit_path || append) {
+ if (!paths || 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 +522,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 +570,246 @@ 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);
+ r = strv_extend_strv(&paths, add, true);
if (r < 0)
- return r;
+ return r;
}
- 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(paths, 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(paths);
+ paths = 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;
+ p->root_dir = root;
+ root = NULL;
+
+ return 0;
+}
- if (strv_isempty(p->sysvrcnd_path)) {
- strv_free(p->sysvrcnd_path);
+void lookup_paths_free(LookupPaths *p) {
+ if (!p)
+ return;
- p->sysvrcnd_path = strv_new(
- SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
- NULL);
- if (!p->sysvrcnd_path)
- return -ENOMEM;
+ 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);
+
+ /* 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. */
+
+ 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;
}
- if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
- return -ENOMEM;
+ 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 (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
+ if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
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);
- }
+ stats[n_stats++] = st;
+ c++;
+ continue;
- if (!strv_isempty(p->sysvrcnd_path)) {
- _cleanup_free_ char *t =
- strv_join(p->sysvrcnd_path, "\n\t");
- if (!t)
- return -ENOMEM;
+ 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*));
+ }
- 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
+ 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;
}
-void lookup_paths_free(LookupPaths *p) {
+int lookup_paths_mkdir_generator(LookupPaths *p) {
+ int r, q;
+
assert(p);
- p->unit_path = strv_free(p->unit_path);
+ if (!p->generator || !p->generator_early || !p->generator_late)
+ return -EINVAL;
-#ifdef HAVE_SYSV_COMPAT
- p->sysvinit_path = strv_free(p->sysvinit_path);
- p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
-#endif
+ 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;
}
-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);
+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);
- zero(*paths);
+ 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);
- return lookup_paths_init(paths,
- scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
- scope == UNIT_FILE_USER,
- root_dir,
- NULL, NULL, NULL);
+ default:
+ assert_not_reached("Hmm, unexpected scope.");
+ }
}
diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h
index 26c83d6111..f9bb2fe237 100644
--- a/src/shared/path-lookup.h
+++ b/src/shared/path-lookup.h
@@ -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"
+
+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;
-int lookup_paths_init_from_scope(LookupPaths *paths,
- UnitFileScope scope,
- const char *root_dir);
+ /* 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);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 35aa60101f..f00624d0f2 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -28,6 +28,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
#include "def.h"
+#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
@@ -231,6 +232,9 @@ static bool enough_memory_for_hibernation(void) {
size_t size = 0, used = 0;
int r;
+ if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
+ return true;
+
r = hibernation_partition_size(&size, &used);
if (r < 0)
return false;
diff --git a/src/shared/tests.c b/src/shared/tests.c
new file mode 100644
index 0000000000..409116290d
--- /dev/null
+++ b/src/shared/tests.c
@@ -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;
+}
diff --git a/src/shared/tests.h b/src/shared/tests.h
new file mode 100644
index 0000000000..93f09013a1
--- /dev/null
+++ b/src/shared/tests.h
@@ -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);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 62cff3a677..059e985463 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -341,6 +341,12 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
if (arg_all)
return true;
+ /* Note that '--all' is not purely a state filter, but also a
+ * filter that hides units that "follow" other units (which is
+ * used for device units that appear under different names). */
+ if (!isempty(u->following))
+ return false;
+
if (!strv_isempty(arg_states))
return true;
@@ -349,7 +355,7 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
if (u->job_id > 0)
return true;
- if (streq(u->active_state, "inactive") || u->following[0])
+ if (streq(u->active_state, "inactive"))
return false;
return true;
@@ -1984,19 +1990,6 @@ static int get_default(int argc, char *argv[], void *userdata) {
return 0;
}
-static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) {
- unsigned i;
-
- assert(changes || n_changes == 0);
-
- for (i = 0; i < n_changes; i++) {
- 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);
- }
-}
-
static int set_default(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *unit = NULL;
int r;
@@ -2013,14 +2006,9 @@ static int set_default(int argc, char *argv[], void *userdata) {
unsigned n_changes = 0;
r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
- if (r < 0)
- return log_error_errno(r, "Failed to set default target: %m");
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
+ unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet);
unit_file_changes_free(changes, n_changes);
- r = 0;
+ return r;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -2295,7 +2283,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 +2383,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;
}
@@ -3109,7 +3097,7 @@ static int set_exit_code(uint8_t code) {
NULL,
"y", code);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
return 0;
}
@@ -3136,7 +3124,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;
@@ -3254,7 +3242,7 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
/* --fail was specified */
if (streq(arg_job_mode, "fail"))
- kill_who = strjoina(arg_kill_who, "-fail", NULL);
+ kill_who = strjoina(arg_kill_who, "-fail");
r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
@@ -4780,34 +4768,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 +4786,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 +4798,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)
@@ -4989,7 +4947,7 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
* reply */
r = 0;
else if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
return r < 0 ? r : 0;
}
@@ -5253,8 +5211,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 +5228,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;
+ siginfo_t status;
+ const char *name;
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;
+ int j;
name = args[f++];
@@ -5295,21 +5259,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, -ERFKILL, -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 +5279,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 +5294,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 +5306,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 +5328,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 +5403,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,23 +5425,20 @@ 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.");
+ unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
if (r < 0)
- return log_error_errno(r, "Operation failed: %m");
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
+ return r;
r = 0;
} else {
_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 +5473,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 +5499,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);
@@ -5554,7 +5513,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
if (expect_carries_install_info) {
r = sd_bus_message_read(reply, "b", &carries_install_info);
@@ -5574,15 +5533,18 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
}
if (carries_install_info == 0)
- log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
- "using systemctl.\n"
+ log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
+ "settings in the [Install] section, and DefaultInstance for template units).\n"
+ "This means they are not meant to be enabled using systemctl.\n"
"Possible reasons for having this kind of units are:\n"
"1) A unit may be statically enabled by being symlinked from another unit's\n"
" .wants/ or .requires/ directory.\n"
"2) A unit's purpose may be to act as a helper for some other unit which has\n"
" a requirement dependency on it.\n"
"3) A unit may be started when needed via activation (socket, path, timer,\n"
- " D-Bus, udev, scripted systemctl call, ...).\n");
+ " D-Bus, udev, scripted systemctl call, ...).\n"
+ "4) In case of template units, the unit is meant to be enabled with some\n"
+ " instance name specified.");
if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
char *new_args[n_changes + 2];
@@ -5637,16 +5599,9 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
unsigned n_changes = 0;
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 < 0)
- return log_error_errno(r, "Can't add dependency: %m");
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
+ unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
unit_file_changes_free(changes, n_changes);
-
+ return r;
} else {
_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;
@@ -5678,39 +5633,29 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
- if (!arg_no_reload)
- r = daemon_reload(argc, argv, userdata);
- else
- r = 0;
+ if (arg_no_reload)
+ return 0;
+ return daemon_reload(argc, argv, userdata);
}
-
- return r;
}
static int preset_all(int argc, char *argv[], void *userdata) {
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
int r;
if (install_client_side()) {
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
- if (r < 0) {
- log_error_errno(r, "Operation failed: %m");
- goto finish;
- }
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
- r = 0;
-
+ unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
+ unit_file_changes_free(changes, n_changes);
+ return r;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -5735,22 +5680,16 @@ static int preset_all(int argc, char *argv[], void *userdata) {
arg_runtime,
arg_force);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
- if (!arg_no_reload)
- r = daemon_reload(argc, argv, userdata);
- else
- r = 0;
+ if (arg_no_reload)
+ return 0;
+ return daemon_reload(argc, argv, userdata);
}
-
-finish:
- unit_file_changes_free(changes, n_changes);
-
- return r;
}
static int unit_is_enabled(int argc, char *argv[], void *userdata) {
@@ -5783,7 +5722,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 +5758,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 +5766,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 +5836,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 +5872,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 +5886,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 +5903,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 +5917,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 +6032,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,13 +6039,12 @@ 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;
STRV_FOREACH(name, names) {
- _cleanup_free_ char *path = NULL;
- char *new_path, *tmp_path;
+ _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL;
r = unit_find_paths(bus, *name, &lp, &path, NULL);
if (r < 0)
@@ -6137,15 +6058,16 @@ 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;
r = strv_push_pair(paths, new_path, tmp_path);
if (r < 0)
return log_oom();
+ new_path = tmp_path = NULL;
}
return 0;
@@ -6324,6 +6246,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"
@@ -6751,7 +6675,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_ROOT:
- r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ r = parse_path_argument_and_warn(optarg, false, &arg_root);
if (r < 0)
return r;
break;
@@ -6992,7 +6916,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 +7371,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 +7418,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 +7445,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.");
diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h
index fa6ab9ad3b..5772d5794a 100644
--- a/src/systemd/sd-lldp.h
+++ b/src/systemd/sd-lldp.h
@@ -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 {
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 59e1a3e921..fe4bbeeb75 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -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, -ERFKILL, -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;
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index ad15075a5b..4eb8fcd773 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -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;
}
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index ca66f5b684..361d1e7b0b 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -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;
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 901cc44af6..77ef4e8b2a 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -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);
}
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
index cd250ca7b8..2d73c9743b 100644
--- a/src/test/test-install-root.c
+++ b/src/test/test-install-root.c
@@ -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);
@@ -78,7 +80,7 @@ static void test_basic_mask_and_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED);
/* Enabling a masked unit should fail! */
- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN);
+ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ERFKILL);
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
@@ -105,7 +107,7 @@ static void test_basic_mask_and_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
/* Enabling it again should succeed but be a NOP */
- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
+ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0);
assert_se(n_changes == 0);
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
@@ -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);
diff --git a/src/test/test-install.c b/src/test/test-install.c
index 874d617621..50315c1d9a 100644
--- a/src/test/test-install.c
+++ b/src/test/test-install.c
@@ -46,6 +46,9 @@ int main(int argc, char* argv[]) {
unsigned n_changes = 0;
UnitFileState state = 0;
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+
h = hashmap_new(&string_hash_ops);
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
assert_se(r == 0);
@@ -65,12 +68,12 @@ int main(int argc, char* argv[]) {
unit_file_list_free(h);
- log_error("enable");
+ log_info("/*** enable **/");
r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
- log_error("enable2");
+ log_info("/*** enable2 **/");
r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
@@ -82,8 +85,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
- log_error("disable");
-
+ log_info("/*** disable ***/");
changes = NULL;
n_changes = 0;
@@ -97,13 +99,13 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
- log_error("mask");
+ log_info("/*** mask ***/");
changes = NULL;
n_changes = 0;
r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
- log_error("mask2");
+ log_info("/*** mask2 ***/");
r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
@@ -114,13 +116,13 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
- log_error("unmask");
+ log_info("/*** unmask ***/");
changes = NULL;
n_changes = 0;
r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
- log_error("unmask2");
+ log_info("/*** unmask2 ***/");
r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
@@ -131,7 +133,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
- log_error("mask");
+ log_info("/*** mask ***/");
changes = NULL;
n_changes = 0;
@@ -145,13 +147,13 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
- log_error("disable");
+ log_info("/*** disable ***/");
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
- log_error("disable2");
+ log_info("/*** disable2 ***/");
r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
@@ -162,7 +164,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
- log_error("umask");
+ log_info("/*** umask ***/");
changes = NULL;
n_changes = 0;
@@ -176,7 +178,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
- log_error("enable files2");
+ log_info("/*** enable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -190,7 +192,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
- log_error("disable files2");
+ log_info("/*** disable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -203,7 +205,7 @@ int main(int argc, char* argv[]) {
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
- log_error("link files2");
+ log_info("/*** link files2 ***/");
changes = NULL;
n_changes = 0;
@@ -217,7 +219,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_LINKED);
- log_error("disable files2");
+ log_info("/*** disable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -230,7 +232,7 @@ int main(int argc, char* argv[]) {
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
- log_error("link files2");
+ log_info("/*** link files2 ***/");
changes = NULL;
n_changes = 0;
@@ -244,7 +246,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_LINKED);
- log_error("reenable files2");
+ log_info("/*** reenable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -258,7 +260,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
- log_error("disable files2");
+ log_info("/*** disable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -270,7 +272,7 @@ int main(int argc, char* argv[]) {
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
- log_error("preset files");
+ log_info("/*** preset files ***/");
changes = NULL;
n_changes = 0;
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 0b2f9e9173..ff9f35cecd 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -69,8 +69,10 @@ static void test_netns(void) {
int r, n = 0;
siginfo_t si;
- if (geteuid() > 0)
- return;
+ if (geteuid() > 0) {
+ log_info("Skipping test: not root");
+ exit(EXIT_TEST_SKIP);
+ }
assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
@@ -124,6 +126,9 @@ int main(int argc, char *argv[]) {
char boot_id[SD_ID128_STRING_MAX];
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL;
+ log_parse_environment();
+ log_open();
+
assert_se(sd_id128_get_boot(&bid) >= 0);
sd_id128_to_string(bid, boot_id);
diff --git a/src/test/test-nss.c b/src/test/test-nss.c
index 9c13288d2e..55af592287 100644
--- a/src/test/test-nss.c
+++ b/src/test/test-nss.c
@@ -381,12 +381,18 @@ static void test_byaddr(void *handle,
#ifdef HAVE_MYHOSTNAME
# define MODULE1 "myhostname\0"
+#else
+# define MODULE1
#endif
#ifdef HAVE_RESOLVED
# define MODULE2 "resolve\0"
+#else
+# define MODULE2
#endif
#ifdef HAVE_MACHINED
# define MODULE3 "mymachines\0"
+#else
+# define MODULE3
#endif
#define MODULE4 "dns\0"
diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c
index 268da002a9..096326d176 100644
--- a/src/test/test-path-lookup.c
+++ b/src/test/test-path-lookup.c
@@ -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;
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index d376dd56c5..5d77e2959c 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -90,6 +90,18 @@ static void test_path(void) {
assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
assert_se(path_equal(path_kill_slashes(p3), "/./"));
}
+
+ assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
+ assert_se(PATH_IN_SET("/bin", "/bin"));
+ assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
+ assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
+ assert_se(!PATH_IN_SET("/", "/abc", "/def"));
+
+ assert_se(path_equal_ptr(NULL, NULL));
+ assert_se(path_equal_ptr("/a", "/a"));
+ assert_se(!path_equal_ptr("/a", "/b"));
+ assert_se(!path_equal_ptr("/a", NULL));
+ assert_se(!path_equal_ptr(NULL, "/a"));
}
static void test_find_binary(const char *self) {
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 1e704a03dc..435cafd83a 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -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++) {
diff --git a/src/test/test-rbtree.c b/src/test/test-rbtree.c
deleted file mode 100644
index 8ae416c557..0000000000
--- a/src/test/test-rbtree.c
+++ /dev/null
@@ -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;
-}
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
index 7f515b53d8..3e9caafc71 100644
--- a/src/test/test-sched-prio.c
+++ b/src/test/test-sched-prio.c
@@ -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;
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index fea1f848cd..fc01dcfaf1 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -358,7 +358,7 @@ static void test_strv_extend_strv_concat(void) {
}
static void test_strv_extend_strv(void) {
- _cleanup_strv_free_ char **a = NULL, **b = NULL;
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL;
a = strv_new("abc", "def", "ghi", NULL);
b = strv_new("jkl", "mno", "abc", "pqr", NULL);
@@ -373,8 +373,14 @@ static void test_strv_extend_strv(void) {
assert_se(streq(a[3], "jkl"));
assert_se(streq(a[4], "mno"));
assert_se(streq(a[5], "pqr"));
-
assert_se(strv_length(a) == 6);
+
+ assert_se(strv_extend_strv(&n, b, false) >= 0);
+ assert_se(streq(n[0], "jkl"));
+ assert_se(streq(n[1], "mno"));
+ assert_se(streq(n[2], "abc"));
+ assert_se(streq(n[3], "pqr"));
+ assert_se(strv_length(n) == 4);
}
static void test_strv_extend(void) {
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index 8522e9925c..e965b4494a 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "fs-util.h"
+#include "log.h"
#include "missing.h"
#include "selinux-util.h"
#include "signal-util.h"
@@ -39,39 +40,31 @@ static int fake_filesystems(void) {
const char *src;
const char *target;
const char *error;
+ bool ignore_mount_error;
} fakefss[] = {
- { "test/tmpfs/sys", "/sys", "failed to mount test /sys" },
- { "test/tmpfs/dev", "/dev", "failed to mount test /dev" },
- { "test/run", "/run", "failed to mount test /run" },
- { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" },
- { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" },
+ { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false },
+ { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false },
+ { "test/run", "/run", "failed to mount test /run", false },
+ { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true },
+ { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
};
unsigned int i;
- int err;
- err = unshare(CLONE_NEWNS);
- if (err < 0) {
- err = -errno;
- fprintf(stderr, "failed to call unshare(): %m\n");
- goto out;
- }
+ if (unshare(CLONE_NEWNS) < 0)
+ return log_error_errno(errno, "failed to call unshare(): %m");
- if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
- err = -errno;
- fprintf(stderr, "failed to mount / as private: %m\n");
- goto out;
- }
+ if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0)
+ return log_error_errno(errno, "failed to mount / as private: %m");
for (i = 0; i < ELEMENTSOF(fakefss); i++) {
- err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
- if (err < 0) {
- err = -errno;
- fprintf(stderr, "%s %m\n", fakefss[i].error);
- return err;
+ if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
+ log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
+ if (!fakefss[i].ignore_mount_error)
+ return -errno;
}
}
-out:
- return err;
+
+ return 0;
}
int main(int argc, char *argv[]) {
@@ -84,6 +77,9 @@ int main(int argc, char *argv[]) {
const char *action;
int err;
+ log_parse_environment();
+ log_open();
+
err = fake_filesystems();
if (err < 0)
return EXIT_FAILURE;
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index cc6c61ba63..114ddf8478 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -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();
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 3de94ef425..2fd83f321c 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -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;
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index efd264b34d..2053d35a67 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -94,6 +94,7 @@ typedef enum ItemType {
/* These ones take globs */
WRITE_FILE = 'w',
+ EMPTY_DIRECTORY = 'e',
SET_XATTR = 't',
RECURSIVE_SET_XATTR = 'T',
SET_ACL = 'a',
@@ -179,6 +180,7 @@ static bool needs_glob(ItemType t) {
IGNORE_DIRECTORY_PATH,
REMOVE_PATH,
RECURSIVE_REMOVE_PATH,
+ EMPTY_DIRECTORY,
ADJUST_MODE,
RELABEL_PATH,
RECURSIVE_RELABEL_PATH,
@@ -195,6 +197,7 @@ static bool takes_ownership(ItemType t) {
CREATE_FILE,
TRUNCATE_FILE,
CREATE_DIRECTORY,
+ EMPTY_DIRECTORY,
TRUNCATE_DIRECTORY,
CREATE_SUBVOLUME,
CREATE_SUBVOLUME_INHERIT_QUOTA,
@@ -1217,7 +1220,6 @@ static int create_item(Item *i) {
case CREATE_SUBVOLUME:
case CREATE_SUBVOLUME_INHERIT_QUOTA:
case CREATE_SUBVOLUME_NEW_QUOTA:
-
RUN_WITH_UMASK(0000)
mkdir_parents_label(i->path, 0755);
@@ -1276,11 +1278,11 @@ static int create_item(Item *i) {
if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
if (r == -ENOTTY)
- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path);
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
else if (r == -EROFS)
- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
else if (r == -ENOPROTOOPT)
- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path);
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
else if (r < 0)
q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
else if (r > 0)
@@ -1289,6 +1291,9 @@ static int create_item(Item *i) {
log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
}
+ /* fall through */
+
+ case EMPTY_DIRECTORY:
r = path_set_perms(i, i->path);
if (q < 0)
return q;
@@ -1298,7 +1303,6 @@ static int create_item(Item *i) {
break;
case CREATE_FIFO:
-
RUN_WITH_UMASK(0000) {
mac_selinux_create_file_prepare(i->path, S_IFIFO);
r = mkfifo(i->path, i->mode);
@@ -1535,47 +1539,20 @@ static int remove_item_instance(Item *i, const char *instance) {
}
static int remove_item(Item *i) {
- int r = 0;
-
assert(i);
log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
switch (i->type) {
- case CREATE_FILE:
- case TRUNCATE_FILE:
- case CREATE_DIRECTORY:
- case CREATE_SUBVOLUME:
- case CREATE_SUBVOLUME_INHERIT_QUOTA:
- case CREATE_SUBVOLUME_NEW_QUOTA:
- case CREATE_FIFO:
- case CREATE_SYMLINK:
- case CREATE_CHAR_DEVICE:
- case CREATE_BLOCK_DEVICE:
- case IGNORE_PATH:
- case IGNORE_DIRECTORY_PATH:
- case ADJUST_MODE:
- case RELABEL_PATH:
- case RECURSIVE_RELABEL_PATH:
- case WRITE_FILE:
- case COPY_FILES:
- case SET_XATTR:
- case RECURSIVE_SET_XATTR:
- case SET_ACL:
- case RECURSIVE_SET_ACL:
- case SET_ATTRIBUTE:
- case RECURSIVE_SET_ATTRIBUTE:
- break;
-
case REMOVE_PATH:
case TRUNCATE_DIRECTORY:
case RECURSIVE_REMOVE_PATH:
- r = glob_item(i, remove_item_instance, false);
- break;
- }
+ return glob_item(i, remove_item_instance, false);
- return r;
+ default:
+ return 0;
+ }
}
static int clean_item_instance(Item *i, const char* instance) {
@@ -1630,8 +1607,6 @@ static int clean_item_instance(Item *i, const char* instance) {
}
static int clean_item(Item *i) {
- int r = 0;
-
assert(i);
log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
@@ -1641,19 +1616,17 @@ static int clean_item(Item *i) {
case CREATE_SUBVOLUME:
case CREATE_SUBVOLUME_INHERIT_QUOTA:
case CREATE_SUBVOLUME_NEW_QUOTA:
+ case EMPTY_DIRECTORY:
case TRUNCATE_DIRECTORY:
case IGNORE_PATH:
case COPY_FILES:
clean_item_instance(i, i->path);
- break;
+ return 0;
case IGNORE_DIRECTORY_PATH:
- r = glob_item(i, clean_item_instance, false);
- break;
+ return glob_item(i, clean_item_instance, false);
default:
- break;
+ return 0;
}
-
- return r;
}
static int process_item_array(ItemArray *array);
@@ -1879,6 +1852,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
case CREATE_SUBVOLUME:
case CREATE_SUBVOLUME_INHERIT_QUOTA:
case CREATE_SUBVOLUME_NEW_QUOTA:
+ case EMPTY_DIRECTORY:
case TRUNCATE_DIRECTORY:
case CREATE_FIFO:
case IGNORE_PATH:
@@ -2198,7 +2172,8 @@ static int parse_argv(int argc, char *argv[]) {
}
static int read_config_file(const char *fn, bool ignore_enoent) {
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_fclose_ FILE *_f = NULL;
+ FILE *f;
char line[LINE_MAX];
Iterator iterator;
unsigned v = 0;
@@ -2207,16 +2182,23 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
assert(fn);
- r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
- if (r < 0) {
- if (ignore_enoent && r == -ENOENT) {
- log_debug_errno(r, "Failed to open \"%s\": %m", fn);
- return 0;
- }
+ if (streq(fn, "-")) {
+ log_debug("Reading config from stdin.");
+ fn = "<stdin>";
+ f = stdin;
+ } else {
+ r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &_f);
+ if (r < 0) {
+ if (ignore_enoent && r == -ENOENT) {
+ log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
+ return 0;
+ }
- return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
+ return log_error_errno(r, "Failed to open '%s': %m", fn);
+ }
+ log_debug("Reading config file \"%s\".", fn);
+ f = _f;
}
- log_debug("Reading config file \"%s\".", fn);
FOREACH_LINE(line, f, break) {
char *l;
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index b5f7f0d512..c0ef073476 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -40,7 +40,7 @@ static void sig_handler(int signum) {
static void print_device(struct udev_device *device, const char *source, int prop) {
struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n",
source,
ts.tv_sec, ts.tv_nsec/1000,
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 243df7386f..e9dd2f47c7 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -400,10 +400,11 @@ static void worker_spawn(Manager *manager, struct event *event) {
goto out;
}
- /* request TERM signal if parent exits */
- prctl(PR_SET_PDEATHSIG, SIGTERM);
+ /* Request TERM signal if parent exits.
+ Ignore error, not much we can do in that case. */
+ (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
- /* reset OOM score, we only protect the main daemon */
+ /* Reset OOM score, we only protect the main daemon. */
write_string_file("/proc/self/oom_score_adj", "0", 0);
for (;;) {
diff --git a/test/TEST-07-ISSUE-1981/test.sh b/test/TEST-07-ISSUE-1981/test.sh
index dcb6ece4d4..d97c4ec27d 100755
--- a/test/TEST-07-ISSUE-1981/test.sh
+++ b/test/TEST-07-ISSUE-1981/test.sh
@@ -8,7 +8,8 @@ TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/1981"
test_run() {
dwarn "skipping QEMU"
if check_nspawn; then
- timeout --foreground 30s systemd-nspawn --kill-signal=SIGKILL --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND
+ NSPAWN_TIMEOUT=30s
+ run_nspawn
check_result_nspawn || return 1
else
dwarn "can't run systemd-nspawn, skipping"
diff --git a/test/test-functions b/test/test-functions
index 8bbcddab59..b07c500339 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -8,6 +8,7 @@ LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE"
KERNEL_VER=${KERNEL_VER-$(uname -r)}
KERNEL_MODS="/lib/modules/$KERNEL_VER/"
QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
+NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
FSTYPE="${FSTYPE:-ext3}"
if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
@@ -96,8 +97,12 @@ $KERNEL_APPEND \
}
run_nspawn() {
+ local _nspawn_cmd="../../systemd-nspawn --register=no --kill-signal=SIGKILL --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND"
+ if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
+ _nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
+ fi
set -x
- ../../systemd-nspawn --register=no --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND
+ $_nspawn_cmd
}
setup_basic_environment() {