summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am77
-rw-r--r--TODO7
-rw-r--r--configure.ac111
-rw-r--r--hwdb/60-keyboard.hwdb4
-rw-r--r--man/machine-id.xml29
-rw-r--r--man/systemctl.xml12
-rw-r--r--man/systemd-gpt-auto-generator.xml5
-rw-r--r--man/systemd.exec.xml94
-rw-r--r--man/systemd.link.xml14
-rw-r--r--man/systemd.mount.xml19
-rw-r--r--man/systemd.network.xml7
-rw-r--r--man/systemd.service.xml6
-rw-r--r--src/basic/env-util.c3
-rw-r--r--src/basic/extract-word.c2
-rw-r--r--src/basic/missing.h27
-rw-r--r--src/basic/virt.c2
-rw-r--r--src/core/dbus-execute.c2
-rw-r--r--src/core/dbus-job.c121
-rw-r--r--src/core/dbus-job.h4
-rw-r--r--src/core/dbus-manager.c22
-rw-r--r--src/core/dbus-unit.c25
-rw-r--r--src/core/dbus.c16
-rw-r--r--src/core/device.c2
-rw-r--r--src/core/execute.c3
-rw-r--r--src/core/execute.h1
-rw-r--r--src/core/job.c257
-rw-r--r--src/core/job.h16
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c1
-rw-r--r--src/core/manager.c41
-rw-r--r--src/core/manager.h6
-rw-r--r--src/core/namespace.c416
-rw-r--r--src/core/org.freedesktop.systemd1.conf16
-rw-r--r--src/core/unit.c18
-rw-r--r--src/core/unit.h3
-rw-r--r--src/fstab-generator/fstab-generator.c21
-rw-r--r--src/libsystemd-network/dhcp-internal.h5
-rw-r--r--src/libsystemd-network/dhcp-network.c10
-rw-r--r--src/libsystemd-network/dhcp-packet.c6
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c25
-rw-r--r--src/libsystemd-network/test-dhcp-client.c2
-rw-r--r--src/libsystemd/sd-bus/busctl-introspect.c86
-rw-r--r--src/libsystemd/sd-network/sd-network.c14
-rw-r--r--src/network/.gitignore1
-rw-r--r--src/network/netdev/.gitignore1
-rw-r--r--src/network/netdev/bond.c (renamed from src/network/networkd-netdev-bond.c)2
-rw-r--r--src/network/netdev/bond.h (renamed from src/network/networkd-netdev-bond.h)2
-rw-r--r--src/network/netdev/bridge.c (renamed from src/network/networkd-netdev-bridge.c)4
-rw-r--r--src/network/netdev/bridge.h (renamed from src/network/networkd-netdev-bridge.h)2
-rw-r--r--src/network/netdev/dummy.c (renamed from src/network/networkd-netdev-dummy.c)2
-rw-r--r--src/network/netdev/dummy.h (renamed from src/network/networkd-netdev-dummy.h)2
-rw-r--r--src/network/netdev/ipvlan.c (renamed from src/network/networkd-netdev-ipvlan.c)2
-rw-r--r--src/network/netdev/ipvlan.h (renamed from src/network/networkd-netdev-ipvlan.h)2
-rw-r--r--src/network/netdev/macvlan.c (renamed from src/network/networkd-netdev-macvlan.c)2
-rw-r--r--src/network/netdev/macvlan.h (renamed from src/network/networkd-netdev-macvlan.h)2
-rw-r--r--src/network/netdev/netdev-gperf.gperf (renamed from src/network/networkd-netdev-gperf.gperf)22
-rw-r--r--src/network/netdev/netdev.c (renamed from src/network/networkd-netdev.c)17
-rw-r--r--src/network/netdev/netdev.h (renamed from src/network/networkd-netdev.h)0
-rw-r--r--src/network/netdev/tunnel.c (renamed from src/network/networkd-netdev-tunnel.c)2
-rw-r--r--src/network/netdev/tunnel.h (renamed from src/network/networkd-netdev-tunnel.h)2
-rw-r--r--src/network/netdev/tuntap.c (renamed from src/network/networkd-netdev-tuntap.c)2
-rw-r--r--src/network/netdev/tuntap.h (renamed from src/network/networkd-netdev-tuntap.h)2
-rw-r--r--src/network/netdev/vcan.c (renamed from src/network/networkd-netdev-vcan.c)2
-rw-r--r--src/network/netdev/vcan.h (renamed from src/network/networkd-netdev-vcan.h)2
-rw-r--r--src/network/netdev/veth.c (renamed from src/network/networkd-netdev-veth.c)2
-rw-r--r--src/network/netdev/veth.h (renamed from src/network/networkd-netdev-veth.h)2
-rw-r--r--src/network/netdev/vlan.c (renamed from src/network/networkd-netdev-vlan.c)2
-rw-r--r--src/network/netdev/vlan.h (renamed from src/network/networkd-netdev-vlan.h)2
-rw-r--r--src/network/netdev/vrf.c (renamed from src/network/networkd-netdev-vrf.c)2
-rw-r--r--src/network/netdev/vrf.h (renamed from src/network/networkd-netdev-vrf.h)2
-rw-r--r--src/network/netdev/vxlan.c (renamed from src/network/networkd-netdev-vxlan.c)2
-rw-r--r--src/network/netdev/vxlan.h (renamed from src/network/networkd-netdev-vxlan.h)2
-rw-r--r--src/network/networkd-address-pool.c2
-rw-r--r--src/network/networkd-address.c2
-rw-r--r--src/network/networkd-brvlan.c4
-rw-r--r--src/network/networkd-conf.c2
-rw-r--r--src/network/networkd-conf.h2
-rw-r--r--src/network/networkd-dhcp4.c10
-rw-r--r--src/network/networkd-dhcp6.c4
-rw-r--r--src/network/networkd-fdb.c3
-rw-r--r--src/network/networkd-gperf.gperf1
-rw-r--r--src/network/networkd-ipv4ll.c5
-rw-r--r--src/network/networkd-link-bus.c2
-rw-r--r--src/network/networkd-link.c6
-rw-r--r--src/network/networkd-lldp-tx.c2
-rw-r--r--src/network/networkd-manager-bus.c2
-rw-r--r--src/network/networkd-manager.c2
-rw-r--r--src/network/networkd-manager.h (renamed from src/network/networkd.h)13
-rw-r--r--src/network/networkd-ndisc.c3
-rw-r--r--src/network/networkd-network-bus.c2
-rw-r--r--src/network/networkd-network-gperf.gperf3
-rw-r--r--src/network/networkd-network.c5
-rw-r--r--src/network/networkd-network.h5
-rw-r--r--src/network/networkd-route.c2
-rw-r--r--src/network/networkd.c2
-rw-r--r--src/network/test-network-tables.c8
-rw-r--r--src/network/test-network.c2
-rw-r--r--src/network/wait-online/link.c (renamed from src/network/networkd-wait-online-link.c)4
-rw-r--r--src/network/wait-online/link.h (renamed from src/network/networkd-wait-online-link.h)5
-rw-r--r--src/network/wait-online/manager.c (renamed from src/network/networkd-wait-online-manager.c)4
-rw-r--r--src/network/wait-online/manager.h (renamed from src/network/networkd-wait-online.h)3
-rw-r--r--src/network/wait-online/wait-online.c (renamed from src/network/networkd-wait-online.c)2
-rw-r--r--src/nspawn/nspawn.c12
-rw-r--r--src/resolve/resolved-link.c61
-rw-r--r--src/resolve/resolved-resolv-conf.c2
-rw-r--r--src/resolve/resolved.c4
-rw-r--r--src/shared/bus-unit-util.c21
-rw-r--r--src/shared/bus-util.c37
-rw-r--r--src/shared/bus-util.h2
-rw-r--r--src/shared/condition.c3
-rw-r--r--src/shared/nsflags.c5
-rw-r--r--src/systemctl/systemctl.c99
-rw-r--r--src/systemd/sd-dhcp-client.h3
-rw-r--r--src/test/test-execute.c13
-rw-r--r--src/test/test-nss.c190
-rw-r--r--src/timesync/timesyncd-manager.c4
-rw-r--r--src/udev/net/ethtool-util.c209
-rw-r--r--src/udev/net/ethtool-util.h18
-rw-r--r--src/udev/net/link-config-gperf.gperf1
-rw-r--r--src/udev/net/link-config.c30
-rw-r--r--src/udev/net/link-config.h1
-rw-r--r--test/test-execute/exec-restrict-namespaces-mnt-blacklist.service7
-rw-r--r--test/test-execute/exec-restrict-namespaces-mnt.service7
-rw-r--r--test/test-execute/exec-restrict-namespaces-no.service7
-rw-r--r--test/test-execute/exec-restrict-namespaces-yes.service7
-rw-r--r--test/test-functions51
-rw-r--r--units/sys-fs-fuse-connections.mount1
127 files changed, 1801 insertions, 757 deletions
diff --git a/Makefile.am b/Makefile.am
index 50da458918..47c2ec8a8d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -633,7 +633,6 @@ EXTRA_DIST += \
units/halt-local.service.in
GENERAL_ALIASES += \
- $(systemunitdir)/reboot.target $(pkgsysconfdir)/system/ctrl-alt-del.target \
$(systemunitdir)/machines.target $(pkgsysconfdir)/system/multi-user.target.wants/machines.target
dist_doc_DATA = \
@@ -1685,6 +1684,10 @@ EXTRA_DIST += \
test/test-execute/exec-runtimedirectory-mode.service \
test/test-execute/exec-runtimedirectory-owner.service \
test/test-execute/exec-runtimedirectory-owner-nfsnobody.service \
+ test/test-execute/exec-restrict-namespaces-no.service \
+ test/test-execute/exec-restrict-namespaces-yes.service \
+ test/test-execute/exec-restrict-namespaces-mnt.service \
+ test/test-execute/exec-restrict-namespaces-mnt-blacklist.service \
test/bus-policy/hello.conf \
test/bus-policy/methods.conf \
test/bus-policy/ownerships.conf \
@@ -5611,37 +5614,39 @@ libnetworkd_core_la_CFLAGS = \
libnetworkd_core_la_SOURCES = \
src/libsystemd-network/network-internal.h \
- src/network/networkd.h \
+ src/network/netdev/netdev.h \
+ src/network/netdev/netdev.c \
+ src/network/netdev/vrf.h \
+ src/network/netdev/vrf.c \
+ src/network/netdev/tunnel.h \
+ src/network/netdev/tunnel.c \
+ src/network/netdev/veth.h \
+ src/network/netdev/veth.c \
+ src/network/netdev/vxlan.h \
+ src/network/netdev/vxlan.c \
+ src/network/netdev/vlan.h \
+ src/network/netdev/vlan.c \
+ src/network/netdev/macvlan.h \
+ src/network/netdev/macvlan.c \
+ src/network/netdev/ipvlan.h \
+ src/network/netdev/ipvlan.c \
+ src/network/netdev/dummy.h \
+ src/network/netdev/dummy.c \
+ src/network/netdev/tuntap.h \
+ src/network/netdev/tuntap.c \
+ src/network/netdev/bond.h \
+ src/network/netdev/bond.c \
+ src/network/netdev/bridge.h \
+ src/network/netdev/bridge.c \
+ src/network/netdev/vcan.h \
+ src/network/netdev/vcan.c \
+ src/network/networkd-manager.h \
+ src/network/networkd-manager.c \
+ src/network/networkd-manager-bus.c \
src/network/networkd-conf.h \
src/network/networkd-conf.c \
src/network/networkd-link.h \
src/network/networkd-link.c \
- src/network/networkd-netdev.h \
- src/network/networkd-netdev.c \
- src/network/networkd-netdev-vrf.h \
- src/network/networkd-netdev-vrf.c \
- src/network/networkd-netdev-tunnel.h \
- src/network/networkd-netdev-tunnel.c \
- src/network/networkd-netdev-veth.h \
- src/network/networkd-netdev-veth.c \
- src/network/networkd-netdev-vxlan.h \
- src/network/networkd-netdev-vxlan.c \
- src/network/networkd-netdev-vlan.h \
- src/network/networkd-netdev-vlan.c \
- src/network/networkd-netdev-macvlan.h \
- src/network/networkd-netdev-macvlan.c \
- src/network/networkd-netdev-ipvlan.h \
- src/network/networkd-netdev-ipvlan.c \
- src/network/networkd-netdev-dummy.h \
- src/network/networkd-netdev-dummy.c \
- src/network/networkd-netdev-tuntap.h \
- src/network/networkd-netdev-tuntap.c \
- src/network/networkd-netdev-bond.h \
- src/network/networkd-netdev-bond.c \
- src/network/networkd-netdev-bridge.h \
- src/network/networkd-netdev-bridge.c \
- src/network/networkd-netdev-vcan.h \
- src/network/networkd-netdev-vcan.c \
src/network/networkd-link-bus.c \
src/network/networkd-ipv4ll.c \
src/network/networkd-dhcp4.c \
@@ -5655,8 +5660,6 @@ libnetworkd_core_la_SOURCES = \
src/network/networkd-address.c \
src/network/networkd-route.h \
src/network/networkd-route.c \
- src/network/networkd-manager.c \
- src/network/networkd-manager-bus.c \
src/network/networkd-fdb.h \
src/network/networkd-fdb.c \
src/network/networkd-brvlan.h \
@@ -5671,7 +5674,7 @@ libnetworkd_core_la_SOURCES = \
nodist_libnetworkd_core_la_SOURCES = \
src/network/networkd-gperf.c \
src/network/networkd-network-gperf.c \
- src/network/networkd-netdev-gperf.c
+ src/network/netdev/netdev-gperf.c
libnetworkd_core_la_LIBADD = \
libsystemd-network.la \
@@ -5685,11 +5688,11 @@ systemd_networkd_wait_online_CFLAGS = \
systemd_networkd_wait_online_SOURCES = \
src/libsystemd-network/network-internal.h \
- src/network/networkd-wait-online.h \
- src/network/networkd-wait-online-link.h \
- src/network/networkd-wait-online.c \
- src/network/networkd-wait-online-manager.c \
- src/network/networkd-wait-online-link.c
+ src/network/wait-online/link.h \
+ src/network/wait-online/link.c \
+ src/network/wait-online/manager.h \
+ src/network/wait-online/manager.c \
+ src/network/wait-online/wait-online.c
systemd_networkd_wait_online_LDADD = \
libsystemd-network.la \
@@ -5775,7 +5778,7 @@ endif
gperf_gperf_sources += \
src/network/networkd-gperf.gperf \
src/network/networkd-network-gperf.gperf \
- src/network/networkd-netdev-gperf.gperf
+ src/network/netdev/netdev-gperf.gperf
EXTRA_DIST += \
units/systemd-networkd.service.m4.in \
diff --git a/TODO b/TODO
index baaac9407f..7cc8c9dde3 100644
--- a/TODO
+++ b/TODO
@@ -29,6 +29,11 @@ Janitorial Clean-ups:
Features:
+* replace all canonicalize_file_name() invocations by chase_symlinks(), in
+ particulr those where a rootdir is relevant.
+
+* add parse_ip_port() or so, that is like safe_atou16() but checks for != 0
+
* drop nss-myhostname in favour of nss-resolve?
* drop internal dlopen() based nss-dns fallback in nss-resolve, and rely on the
@@ -560,7 +565,6 @@ Features:
- man: maybe sort directives in man pages, and take sections from --help and apply them to man too
* systemctl:
- - systemctl list-jobs - show dependencies
- add systemctl switch to dump transaction without executing it
- Add a verbose mode to "systemctl start" and friends that explains what is being done or not done
- "systemctl disable" on a static unit prints no message and does
@@ -735,7 +739,6 @@ Features:
- maybe introduce WantsMountsFor=? Usecase:
http://lists.freedesktop.org/archives/systemd-devel/2015-January/027729.html
- recreate systemd's D-Bus private socket file on SIGUSR2
- - GC unreferenced jobs (such as .device jobs)
- move PAM code into its own binary
- when we automatically restart a service, ensure we restart its rdeps, too.
- hide PAM options in fragment parser when compile time disabled
diff --git a/configure.ac b/configure.ac
index 7f6b3b937c..65eaae1ae0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -259,7 +259,7 @@ AC_CHECK_SIZEOF(rlim_t,,[
# we use python to build the man page index
have_python=no
AC_ARG_WITH([python],
- [AS_HELP_STRING([--without-python], [Disable building the man page index and systemd-python (default: test)])])
+ [AS_HELP_STRING([--without-python], [disable building the man page index and systemd-python (default: test)])])
have_lxml=no
AS_IF([test "x$with_python" != "xno"], [
@@ -319,9 +319,10 @@ AC_CHECK_DECLS([
#include <linux/random.h>
]])
-AC_CHECK_TYPES([char16_t, char32_t, key_serial_t],
+AC_CHECK_TYPES([char16_t, char32_t, key_serial_t, struct ethtool_link_settings],
[], [], [[
#include <uchar.h>
+#include <linux/ethtool.h>
]])
AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
@@ -454,7 +455,7 @@ AM_CONDITIONAL(HAVE_LIBMOUNT, [test "$have_libmount" = "yes"])
# ------------------------------------------------------------------------------
have_seccomp=no
-AC_ARG_ENABLE(seccomp, AS_HELP_STRING([--disable-seccomp], [Disable optional SECCOMP support]))
+AC_ARG_ENABLE(seccomp, AS_HELP_STRING([--disable-seccomp], [disable optional SECCOMP support]))
if test "x$enable_seccomp" != "xno"; then
PKG_CHECK_MODULES(SECCOMP, [libseccomp >= 2.3.1],
[AC_DEFINE(HAVE_SECCOMP, 1, [Define if seccomp is available])
@@ -469,7 +470,7 @@ AM_CONDITIONAL(HAVE_SECCOMP, [test "$have_seccomp" = "yes"])
# ------------------------------------------------------------------------------
have_ima=yes
-AC_ARG_ENABLE([ima], AS_HELP_STRING([--disable-ima],[Disable optional IMA support]),
+AC_ARG_ENABLE([ima], AS_HELP_STRING([--disable-ima], [disable optional IMA support]),
[case "${enableval}" in
yes) have_ima=yes ;;
no) have_ima=no ;;
@@ -483,7 +484,7 @@ fi
# ------------------------------------------------------------------------------
have_selinux=no
-AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [Disable optional SELINUX support]))
+AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [disable optional SELINUX support]))
if test "x$enable_selinux" != "xno"; then
PKG_CHECK_MODULES([SELINUX], [libselinux >= 2.1.9],
[AC_DEFINE(HAVE_SELINUX, 1, [Define if SELinux is available])
@@ -497,7 +498,7 @@ fi
AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"])
have_apparmor=no
-AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--disable-apparmor], [Disable optional AppArmor support]))
+AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--disable-apparmor], [disable optional AppArmor support]))
if test "x$enable_apparmor" != "xno"; then
PKG_CHECK_MODULES([APPARMOR], [libapparmor],
[AC_DEFINE(HAVE_APPARMOR, 1, [Define if AppArmor is available])
@@ -529,7 +530,7 @@ AS_IF([test "x$enable_wheel_group" != "xno"], [
AC_ARG_WITH(debug-shell,
AS_HELP_STRING([--with-debug-shell=PATH],
- [Path to debug shell binary]),
+ [path to debug shell binary]),
[SUSHELL="$withval"],[
AS_IF([test "x${have_selinux}" != "xno"], [SUSHELL="/sbin/sushell"] , [SUSHELL="/bin/sh"])])
@@ -537,7 +538,7 @@ AC_SUBST(SUSHELL)
AC_ARG_WITH([debug-tty],
AS_HELP_STRING([--with-debug-tty=PATH],
- [Specify the tty device for debug shell]),
+ [specify the tty device for debug shell]),
[DEBUGTTY="$withval"],
[DEBUGTTY=/dev/tty9])
@@ -545,7 +546,7 @@ AC_SUBST(DEBUGTTY)
AC_ARG_WITH([certificate-root],
AS_HELP_STRING([--with-certificate-root=PATH],
- [Specify the prefix for TLS certificates [/etc/ssl]]),
+ [specify the prefix for TLS certificates [/etc/ssl]]),
[CERTIFICATEROOT="$withval"],
[CERTIFICATEROOT="/etc/ssl"])
@@ -553,7 +554,7 @@ AC_SUBST(CERTIFICATEROOT)
AC_ARG_WITH([support-url],
AS_HELP_STRING([--with-support-url=URL],
- [Specify the support URL to show in catalog entries included in systemd]),
+ [specify the support URL to show in catalog entries included in systemd]),
[SUPPORT_URL="$withval"],
[SUPPORT_URL=http://lists.freedesktop.org/mailman/listinfo/systemd-devel])
@@ -561,7 +562,7 @@ AC_SUBST(SUPPORT_URL)
AC_ARG_WITH([nobody-user],
AS_HELP_STRING([--with-nobody-user=NAME],
- [Specify the name of the nobody user (the one with UID 65534)]),
+ [specify the name of the nobody user (the one with UID 65534)]),
[NOBODY_USER_NAME="$withval"],
[NOBODY_USER_NAME=nobody])
@@ -570,7 +571,7 @@ AC_DEFINE_UNQUOTED(NOBODY_USER_NAME, ["$NOBODY_USER_NAME"], [The name of the nob
AC_ARG_WITH([nobody-group],
AS_HELP_STRING([--with-nobody-group=NAME],
- [Specify the name of the nobody group (the one with GID 65534)]),
+ [specify the name of the nobody group (the one with GID 65534)]),
[NOBODY_GROUP_NAME="$withval"],
[NOBODY_GROUP_NAME=nobody])
@@ -579,7 +580,7 @@ AC_DEFINE_UNQUOTED(NOBODY_GROUP_NAME, ["$NOBODY_GROUP_NAME"], [The name of the n
# ------------------------------------------------------------------------------
have_xz=no
-AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
+AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [disable optional XZ support]))
AS_IF([test "x$enable_xz" != "xno"], [
PKG_CHECK_MODULES(XZ, [ liblzma ],
[AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available])
@@ -592,7 +593,7 @@ AM_CONDITIONAL(HAVE_XZ, [test "$have_xz" = "yes"])
# ------------------------------------------------------------------------------
have_zlib=no
-AC_ARG_ENABLE(zlib, AS_HELP_STRING([--disable-zlib], [Disable optional ZLIB support]))
+AC_ARG_ENABLE(zlib, AS_HELP_STRING([--disable-zlib], [disable optional ZLIB support]))
AS_IF([test "x$enable_zlib" != "xno"], [
PKG_CHECK_MODULES(ZLIB, [ zlib ],
[AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available])
@@ -605,7 +606,7 @@ AM_CONDITIONAL(HAVE_ZLIB, [test "$have_zlib" = "yes"])
# ------------------------------------------------------------------------------
have_bzip2=no
-AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Enable optional BZIP2 support]))
+AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--disable-bzip2], [disable optional BZIP2 support]))
AS_IF([test "x$enable_bzip2" != "xno"], [
AC_CHECK_HEADERS(bzlib.h,
[AC_DEFINE(HAVE_BZIP2, 1, [Define if BZIP2 is available])
@@ -618,7 +619,7 @@ AM_CONDITIONAL(HAVE_BZIP2, [test "$have_bzip2" = "yes"])
# ------------------------------------------------------------------------------
have_lz4=no
-AC_ARG_ENABLE(lz4, AS_HELP_STRING([--disable-lz4], [Disable optional LZ4 support]))
+AC_ARG_ENABLE(lz4, AS_HELP_STRING([--disable-lz4], [disable optional LZ4 support]))
AS_IF([test "x$enable_lz4" != "xno"], [
PKG_CHECK_MODULES(LZ4, [ liblz4 >= 125 ],
[AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available])
@@ -633,7 +634,7 @@ AM_CONDITIONAL(HAVE_COMPRESSION, [test "$have_xz" = "yes" -o "$have_lz4" = "yes"
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([pam],
- AS_HELP_STRING([--disable-pam],[Disable optional PAM support]),
+ AS_HELP_STRING([--disable-pam], [disable optional PAM support]),
[case "${enableval}" in
yes) have_pam=yes ;;
no) have_pam=no ;;
@@ -672,7 +673,7 @@ AM_CONDITIONAL([HAVE_PAM], [test "x$have_pam" != xno])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([acl],
- AS_HELP_STRING([--disable-acl],[Disable optional ACL support]),
+ AS_HELP_STRING([--disable-acl], [disable optional ACL support]),
[case "${enableval}" in
yes) have_acl=yes ;;
no) have_acl=no ;;
@@ -710,7 +711,7 @@ AC_SUBST(ACL_LIBS)
AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno])
# ------------------------------------------------------------------------------
-AC_ARG_ENABLE([smack], AS_HELP_STRING([--disable-smack],[Disable optional SMACK support]),
+AC_ARG_ENABLE([smack], AS_HELP_STRING([--disable-smack], [disable optional SMACK support]),
[case "${enableval}" in
yes) have_smack=yes ;;
no) have_smack=no ;;
@@ -745,7 +746,7 @@ AS_HELP_STRING([--with-smack-default-process-label=STRING],
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([gcrypt],
- AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]),
+ AS_HELP_STRING([--disable-gcrypt], [disable optional GCRYPT support]),
[case "${enableval}" in
yes) have_gcrypt=yes ;;
no) have_gcrypt=no ;;
@@ -797,7 +798,7 @@ AM_CONDITIONAL([HAVE_GCRYPT], [test "x$have_gcrypt" != xno])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([audit],
- AS_HELP_STRING([--disable-audit],[Disable optional AUDIT support]),
+ AS_HELP_STRING([--disable-audit], [disable optional AUDIT support]),
[case "${enableval}" in
yes) have_audit=yes ;;
no) have_audit=no ;;
@@ -835,7 +836,7 @@ AM_CONDITIONAL([HAVE_AUDIT], [test "x$have_audit" != xno])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([elfutils],
- AS_HELP_STRING([--disable-elfutils],[Disable optional ELFUTILS support]),
+ AS_HELP_STRING([--disable-elfutils], [disable optional ELFUTILS support]),
[case "${enableval}" in
yes) have_elfutils=yes ;;
no) have_elfutils=no ;;
@@ -942,7 +943,7 @@ AM_CONDITIONAL(HAVE_REMOTE, [test "$have_microhttpd" = "yes" -o "$have_libcurl"
# ------------------------------------------------------------------------------
have_libidn=no
-AC_ARG_ENABLE(libidn, AS_HELP_STRING([--disable-libidn], [Disable optional LIBIDN support]))
+AC_ARG_ENABLE(libidn, AS_HELP_STRING([--disable-libidn], [disable optional LIBIDN support]))
if test "x$enable_libidn" != "xno"; then
PKG_CHECK_MODULES(LIBIDN, [libidn],
[AC_DEFINE(HAVE_LIBIDN, 1, [Define if libidn is available])
@@ -957,7 +958,7 @@ AM_CONDITIONAL(HAVE_LIBIDN, [test "$have_libidn" = "yes"])
# ------------------------------------------------------------------------------
have_libiptc=no
-AC_ARG_ENABLE(libiptc, AS_HELP_STRING([--disable-libiptc], [Disable optional LIBIPTC support]))
+AC_ARG_ENABLE(libiptc, AS_HELP_STRING([--disable-libiptc], [disable optional LIBIPTC support]))
if test "x$enable_libiptc" != "xno"; then
PKG_CHECK_MODULES(LIBIPTC, [libiptc],
[AC_DEFINE(HAVE_LIBIPTC, 1, [Define if libiptc is available])
@@ -1052,7 +1053,7 @@ AM_CONDITIONAL(ENABLE_LOGIND, [test "$have_logind" = "yes"])
AS_IF([test "$have_logind" = "yes"], [ AC_DEFINE(HAVE_LOGIND, [1], [Logind support available]) ])
AC_ARG_WITH([kill-user-processes],
- [AS_HELP_STRING([--without-kill-user-processes], [Set logind's KillUserProcesses=no by default])])
+ [AS_HELP_STRING([--without-kill-user-processes], [set logind's KillUserProcesses=no by default])])
AS_IF([test "$with_kill_user_processes" != "no"],
[kill_user_processes=true
KILL_USER_PROCESSES=yes],
@@ -1106,7 +1107,7 @@ AM_CONDITIONAL(ENABLE_TIMESYNCD, [test "$have_timesyncd" = "yes"])
AC_ARG_WITH(ntp-servers,
AS_HELP_STRING([--with-ntp-servers=NTPSERVERS],
- [Space-separated list of default NTP servers]),
+ [space-separated list of default NTP servers]),
[NTP_SERVERS="$withval"],
[NTP_SERVERS="time1.google.com time2.google.com time3.google.com time4.google.com"
AC_MSG_WARN([*** Using Google NTP servers.
@@ -1118,7 +1119,7 @@ AC_SUBST(NTP_SERVERS)
AC_ARG_WITH(time-epoch,
AS_HELP_STRING([--with-time-epoch=SECONDS],
- [Time epoch for time clients]),
+ [time epoch for time clients]),
[TIME_EPOCH="$withval"],
[TIME_EPOCH="`stat -c %Y ${srcdir}/NEWS 2>/dev/null || echo 0`"])
@@ -1127,7 +1128,7 @@ AC_DEFINE_UNQUOTED(TIME_EPOCH, [$TIME_EPOCH], [Time Epoch])
# ------------------------------------------------------------------------------
AC_ARG_WITH(system-uid-max,
AS_HELP_STRING([--with-system-uid-max=UID]
- [Maximum UID for system users]),
+ [maximum UID for system users]),
[SYSTEM_UID_MAX="$withval"],
[SYSTEM_UID_MAX="`awk 'BEGIN { uid=999 } /^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }' /etc/login.defs 2>/dev/null || echo 999`"])
@@ -1137,7 +1138,7 @@ AC_SUBST(SYSTEM_UID_MAX)
# ------------------------------------------------------------------------------
AC_ARG_WITH(system-gid-max,
AS_HELP_STRING([--with-system-gid-max=GID]
- [Maximum GID for system groups]),
+ [maximum GID for system groups]),
[SYSTEM_GID_MAX="$withval"],
[SYSTEM_GID_MAX="`awk 'BEGIN { gid=999 } /^\s*SYS_GID_MAX\s+/ { gid=$2 } END { print gid }' /etc/login.defs 2>/dev/null || echo 999`"])
@@ -1184,7 +1185,7 @@ AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"])
AC_ARG_WITH(dns-servers,
AS_HELP_STRING([--with-dns-servers=DNSSERVERS],
- [Space-separated list of default DNS servers]),
+ [space-separated list of default DNS servers]),
[DNS_SERVERS="$withval"],
[DNS_SERVERS="8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844"])
@@ -1193,7 +1194,7 @@ AC_SUBST(DNS_SERVERS)
AC_ARG_WITH(default-dnssec,
AS_HELP_STRING([--with-default-dnssec=MODE],
- [Default DNSSEC mode, defaults to "allow-downgrade"]),
+ [default DNSSEC mode, defaults to "allow-downgrade"]),
[DEFAULT_DNSSEC_MODE="$withval"],
[DEFAULT_DNSSEC_MODE="allow-downgrade"])
@@ -1243,7 +1244,7 @@ AC_SUBST([EFI_ARCH])
AC_SUBST([EFI_MACHINE_TYPE_NAME])
have_gnuefi=no
-AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [Enable optional gnuefi support]))
+AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [enable optional gnuefi support]))
AS_IF([test "x$enable_gnuefi" != "xno"], [
AC_CHECK_HEADERS(efi/${EFI_ARCH}/efibind.h,
[AC_DEFINE(HAVE_GNUEFI, 1, [Define if gnuefi is available])
@@ -1256,14 +1257,14 @@ AS_IF([test "x$enable_gnuefi" != "xno"], [
EFI_LIB_DIR="$efiroot"
AC_ARG_WITH(efi-libdir,
- AS_HELP_STRING([--with-efi-libdir=PATH], [Path to EFI lib directory]),
+ AS_HELP_STRING([--with-efi-libdir=PATH], [path to EFI lib directory]),
[EFI_LIB_DIR="$withval"], [EFI_LIB_DIR="$efiroot"]
)
AC_SUBST([EFI_LIB_DIR])
have_efi_lds=no
AC_ARG_WITH(efi-ldsdir,
- AS_HELP_STRING([--with-efi-ldsdir=PATH], [Path to EFI lds directory]),
+ AS_HELP_STRING([--with-efi-ldsdir=PATH], [path to EFI lds directory]),
[EFI_LDS_DIR="$withval" && AS_IF([test -f "${EFI_LDS_DIR}/elf_${EFI_ARCH}_efi.lds"],
[have_efi_lds=yes])],
[AS_FOR([DIR], [EFI_LDS_DIR], ["${EFI_LIB_DIR}/gnuefi" "${EFI_LIB_DIR}"],
@@ -1276,7 +1277,7 @@ AS_IF([test "x$enable_gnuefi" != "xno"], [
[have_gnuefi=no])])
AC_ARG_WITH(efi-includedir,
- AS_HELP_STRING([--with-efi-includedir=PATH], [Path to EFI include directory]),
+ AS_HELP_STRING([--with-efi-includedir=PATH], [path to EFI include directory]),
[EFI_INC_DIR="$withval"], [EFI_INC_DIR="/usr/include"]
)
AC_SUBST([EFI_INC_DIR])
@@ -1285,7 +1286,7 @@ AM_CONDITIONAL(HAVE_GNUEFI, [test "x$have_gnuefi" = xyes])
# ------------------------------------------------------------------------------
have_tpm=no
-AC_ARG_ENABLE([tpm], AS_HELP_STRING([--enable-tpm],[Enable optional TPM support]),
+AC_ARG_ENABLE([tpm], AS_HELP_STRING([--enable-tpm], [enable optional TPM support]),
[case "${enableval}" in
yes) have_tpm=yes ;;
no) have_tpm=no ;;
@@ -1308,13 +1309,13 @@ AC_DEFINE_UNQUOTED(SD_TPM_PCR, [$SD_TPM_PCR], [TPM PCR register number to use])
# ------------------------------------------------------------------------------
AC_ARG_WITH(rc-local-script-path-start,
AS_HELP_STRING([--with-rc-local-script-path-start=PATH],
- [Path to /etc/rc.local]),
+ [path to /etc/rc.local]),
[RC_LOCAL_SCRIPT_PATH_START="$withval"],
[RC_LOCAL_SCRIPT_PATH_START="/etc/rc.local"])
AC_ARG_WITH(rc-local-script-path-stop,
AS_HELP_STRING([--with-rc-local-script-path-stop=PATH],
- [Path to /usr/sbin/halt.local]),
+ [path to /usr/sbin/halt.local]),
[RC_LOCAL_SCRIPT_PATH_STOP="$withval"],
[RC_LOCAL_SCRIPT_PATH_STOP="/usr/sbin/halt.local"])
@@ -1327,13 +1328,13 @@ AC_SUBST(RC_LOCAL_SCRIPT_PATH_STOP)
# ------------------------------------------------------------------------------
AC_ARG_WITH(kbd-loadkeys,
AS_HELP_STRING([--with-kbd-loadkeys=PATH],
- [Path to loadkeys]),
+ [path to loadkeys]),
[KBD_LOADKEYS="$withval"],
[KBD_LOADKEYS="/usr/bin/loadkeys"])
AC_ARG_WITH(kbd-setfont,
AS_HELP_STRING([--with-kbd-setfont=PATH],
- [Path to setfont]),
+ [path to setfont]),
[KBD_SETFONT="$withval"],
[KBD_SETFONT="/usr/bin/setfont"])
@@ -1345,7 +1346,7 @@ AC_SUBST(KBD_SETFONT)
AC_ARG_WITH(telinit,
AS_HELP_STRING([--with-telinit=PATH],
- [Path to telinit]),
+ [path to telinit]),
[TELINIT="$withval"],
[TELINIT="/lib/sysvinit/telinit"])
@@ -1375,7 +1376,7 @@ fi
AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"])
# ------------------------------------------------------------------------------
-AC_ARG_ENABLE(hwdb, [AC_HELP_STRING([--disable-hwdb], [disable hardware database support])],
+AC_ARG_ENABLE(hwdb, [AS_HELP_STRING([--disable-hwdb], [disable hardware database support])],
enable_hwdb=$enableval, enable_hwdb=yes)
AM_CONDITIONAL(ENABLE_HWDB, [test x$enable_hwdb = xyes])
@@ -1392,13 +1393,13 @@ AM_CONDITIONAL(ENABLE_MANPAGES, [test "x$have_manpages" = "xyes"])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE(hibernate,
- [AC_HELP_STRING([--disable-hibernate], [disable hibernation support])],
+ [AS_HELP_STRING([--disable-hibernate], [disable hibernation support])],
enable_hibernate=$enableval, enable_hibernate=yes)
AM_CONDITIONAL(ENABLE_HIBERNATE, [test x$enable_hibernate = xyes])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE(ldconfig,
- [AC_HELP_STRING([--disable-ldconfig], [disable ldconfig])],
+ [AS_HELP_STRING([--disable-ldconfig], [disable ldconfig])],
enable_ldconfig=$enableval, enable_ldconfig=yes)
AM_CONDITIONAL(ENABLE_LDCONFIG, [test x$enable_ldconfig = xyes])
@@ -1409,13 +1410,13 @@ SYSTEM_SYSVRCND_PATH=/etc/rc.d
AC_ARG_WITH([sysvinit-path],
[AS_HELP_STRING([--with-sysvinit-path=PATH],
- [Specify the path to where the SysV init scripts are located])],
+ [specify the path to where the SysV init scripts are located])],
[SYSTEM_SYSVINIT_PATH="$withval"],
[])
AC_ARG_WITH([sysvrcnd-path],
[AS_HELP_STRING([--with-sysvrcnd-path=PATH],
- [Specify the path to the base directory for the SysV rcN.d directories])],
+ [specify the path to the base directory for the SysV rcN.d directories])],
[SYSTEM_SYSVRCND_PATH="$withval"],
[])
@@ -1437,7 +1438,7 @@ AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes")
AC_ARG_WITH([tty-gid],
[AS_HELP_STRING([--with-tty-gid=GID],
- [Specify the numeric GID of the 'tty' group])],
+ [specify the numeric GID of the 'tty' group])],
[TTY_GID="$withval"],
[TTY_GID="5"])
@@ -1463,7 +1464,7 @@ AC_ARG_WITH([dbussystemservicedir],
AX_NORMALIZE_PATH([with_dbussystemservicedir])
AC_ARG_WITH([bashcompletiondir],
- AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]),
+ AS_HELP_STRING([--with-bashcompletiondir=DIR], [bash completions directory]),
[],
[AS_IF([$($PKG_CONFIG --exists bash-completion)], [
with_bashcompletiondir=$($PKG_CONFIG --variable=completionsdir bash-completion)
@@ -1474,7 +1475,7 @@ AM_CONDITIONAL(ENABLE_BASH_COMPLETION, [test "$with_bashcompletiondir" != "no"])
AX_NORMALIZE_PATH([with_bashcompletiondir])
AC_ARG_WITH([zshcompletiondir],
- AS_HELP_STRING([--with-zshcompletiondir=DIR], [Zsh completions directory]),
+ AS_HELP_STRING([--with-zshcompletiondir=DIR], [zsh completions directory]),
[], [with_zshcompletiondir=${datadir}/zsh/site-functions])
AM_CONDITIONAL(ENABLE_ZSH_COMPLETION, [test "$with_zshcompletiondir" != "no"])
AX_NORMALIZE_PATH([with_zshcompletiondir])
@@ -1492,26 +1493,26 @@ fi
AX_NORMALIZE_PATH([with_rootprefix])
AC_ARG_WITH([rootlibdir],
- AS_HELP_STRING([--with-rootlibdir=DIR], [Root directory for libraries necessary for boot]),
+ AS_HELP_STRING([--with-rootlibdir=DIR], [root directory for libraries necessary for boot]),
[],
[with_rootlibdir=${libdir}])
AX_NORMALIZE_PATH([with_rootlibdir])
AC_ARG_WITH([pamlibdir],
- AS_HELP_STRING([--with-pamlibdir=DIR], [Directory for PAM modules]),
+ AS_HELP_STRING([--with-pamlibdir=DIR], [directory for PAM modules]),
[],
[with_pamlibdir=${with_rootlibdir}/security])
AX_NORMALIZE_PATH([with_pamlibdir])
AC_ARG_WITH([pamconfdir],
- AS_HELP_STRING([--with-pamconfdir=DIR], [Directory for PAM configuration (pass no to disable installing)]),
+ AS_HELP_STRING([--with-pamconfdir=DIR], [directory for PAM configuration (pass no to disable installing)]),
[],
[with_pamconfdir=${sysconfdir}/pam.d])
AM_CONDITIONAL(ENABLE_PAM_CONFIG, [test "$with_pamconfdir" != "no"])
AX_NORMALIZE_PATH([with_pamconfdir])
AC_ARG_ENABLE([split-usr],
- AS_HELP_STRING([--enable-split-usr], [Assume that /bin, /sbin aren\'t symlinks into /usr]),
+ AS_HELP_STRING([--enable-split-usr], [assume that /bin, /sbin aren't symlinks into /usr]),
[],
[AS_IF([test "x${ac_default_prefix}" != "x${with_rootprefix}"], [
enable_split_usr=yes
@@ -1538,13 +1539,13 @@ AS_IF([test x"$cross_compiling" = "xyes"], [], [
])
AC_ARG_ENABLE(tests,
- [AC_HELP_STRING([--disable-tests], [disable tests, or enable extra tests with =unsafe])],
+ [AS_HELP_STRING([--disable-tests], [disable tests, or enable extra tests with =unsafe])],
enable_tests=$enableval, enable_tests=yes)
AM_CONDITIONAL(ENABLE_TESTS, [test x$enable_tests = xyes -o x$enable_tests = xunsafe])
AM_CONDITIONAL(ENABLE_UNSAFE_TESTS, [test x$enable_tests = xunsafe])
AC_ARG_ENABLE(debug,
- [AC_HELP_STRING([--enable-debug@<:@=LIST@:>@], [enable extra debugging (hashmap,mmap-cache)])],
+ [AS_HELP_STRING([--enable-debug@<:@=LIST@:>@], [enable extra debugging (hashmap,mmap-cache)])],
[if test "x$enableval" = "xyes"; then
enableval="hashmap,mmap-cache"
fi
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 9c87aecd30..a78aa5dfee 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -415,6 +415,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:
KEYBOARD_KEY_c6=break
KEYBOARD_KEY_94=reserved
+# Pavilion x360 13 (Prevents random airplane mode activation)
+ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:pvr*
+ KEYBOARD_KEY_d7=unknown
+
# Elitebook
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
diff --git a/man/machine-id.xml b/man/machine-id.xml
index d318ec54ec..a722649de4 100644
--- a/man/machine-id.xml
+++ b/man/machine-id.xml
@@ -53,30 +53,31 @@
<refsect1>
<title>Description</title>
- <para>The <filename>/etc/machine-id</filename> file contains the
- unique machine ID of the local system that is set during
- installation. The machine ID is a single newline-terminated,
- hexadecimal, 32-character, lowercase machine ID string. When
- decoded from hexadecimal, this corresponds with a 16-byte/128-bit
- string.</para>
+ <para>The <filename>/etc/machine-id</filename> file contains the unique machine ID of the local
+ system that is set during installation. The machine ID is a single newline-terminated,
+ hexadecimal, 32-character, lowercase ID. When decoded from hexadecimal, this corresponds to a
+ 16-byte/128-bit value.</para>
<para>The machine ID is usually generated from a random source
during system installation and stays constant for all subsequent
boots. Optionally, for stateless systems, it is generated during
runtime at early boot if it is found to be empty.</para>
- <para>The machine ID does not change based on user configuration
- or when hardware is replaced.</para>
+ <para>The machine ID does not change based on local or network configuration or when hardware is
+ replaced. Due to this and its greater length, it is a more useful replacement for the
+ <citerefentry project='man-pages'><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ call that POSIX specifies.</para>
<para>This machine ID adheres to the same format and logic as the
D-Bus machine ID.</para>
- <para>Programs may use this ID to identify the host with a
- globally unique ID in the network, which does not change even if
- the local network configuration changes. Due to this and its
- greater length, it is a more useful replacement for the
- <citerefentry project='man-pages'><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- call that POSIX specifies.</para>
+ <para>This ID uniquely identifies the host. It should be considered "confidential", and must not
+ be exposed in untrusted environments, in particular on the network. If a stable unique
+ identifier that is tied to the machine is needed for some application, the machine ID or any
+ part of it must not be used directly. Instead the machine ID should be hashed with a
+ cryptographic, keyed hash function, using a fixed, application-specific key. That way the ID
+ will be properly unique, and derived in a constant way from the machine ID but there will be no
+ way to retrieve the original machine ID from the application-specific one.</para>
<para>The
<citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry>
diff --git a/man/systemctl.xml b/man/systemctl.xml
index dfa00e0c03..08c3a268bd 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -209,6 +209,10 @@
<varname>RequiresMountsFor=</varname>). Both explicitly
and implicitly introduced dependencies are shown with
<command>list-dependencies</command>.</para>
+
+ <para>When passed to the <command>list-jobs</command> command, for each printed job show which other jobs are
+ waiting for it. May be combined with <option>--before</option> to show both the jobs waiting for each job as
+ well as all jobs each job is waiting for.</para>
</listitem>
</varlistentry>
@@ -220,6 +224,10 @@
units that are ordered after the specified unit. In other
words, recursively list units following the
<varname>Before=</varname> dependency.</para>
+
+ <para>When passed to the <command>list-jobs</command> command, for each printed job show which other jobs it
+ is waiting for. May be combined with <option>--after</option> to show both the jobs waiting for each job as
+ well as all jobs each job is waiting for.</para>
</listitem>
</varlistentry>
@@ -1388,6 +1396,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<para>List jobs that are in progress. If one or more
<replaceable>PATTERN</replaceable>s are specified, only
jobs for units matching one of them are shown.</para>
+
+ <para>When combined with <option>--after</option> or <option>--before</option> the list is augmented with
+ information on which other job each job is waiting for, and which other jobs are waiting for it, see
+ above.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml
index d26206710f..3af423b553 100644
--- a/man/systemd-gpt-auto-generator.xml
+++ b/man/systemd-gpt-auto-generator.xml
@@ -123,6 +123,11 @@
<entry>On 64-bit ARM systems, the first ARM root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
</row>
<row>
+ <entry>993d8d3d-f80e-4225-855a-9daf8ed7ea97</entry>
+ <entry><filename>Root Partition (Itanium/IA-64)</filename></entry>
+ <entry>On Itanium systems, the first Itanium root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
+ </row>
+ <row>
<entry>933ac7e1-2eb4-4f13-b844-0e14e2aef915</entry>
<entry>Home Partition</entry>
<entry>The first home partition on the disk the root partition is located on is mounted to <filename>/home</filename>.</entry>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 3b39a9c912..2ea4a53d18 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -952,13 +952,19 @@
assigned to this option, the specific list is reset, and all prior assignments have no effect.</para>
<para>Paths in <varname>ReadWritePaths=</varname>, <varname>ReadOnlyPaths=</varname> and
- <varname>InaccessiblePaths=</varname> may be prefixed with <literal>-</literal>, in which case they will be ignored
- when they do not exist. Note that using this setting will disconnect propagation of mounts from the service to
- the host (propagation in the opposite direction continues to work). This means that this setting may not be used
- for services which shall be able to install mount points in the main mount namespace. Note that the effect of
- these settings may be undone by privileged processes. In order to set up an effective sandboxed environment for
- a unit it is thus recommended to combine these settings with either
- <varname>CapabilityBoundingSet=~CAP_SYS_ADMIN</varname> or <varname>SystemCallFilter=~@mount</varname>.</para></listitem>
+ <varname>InaccessiblePaths=</varname> may be prefixed with <literal>-</literal>, in which case they will be
+ ignored when they do not exist. If prefixed with <literal>+</literal> the paths are taken relative to the root
+ directory of the unit, as configured with <varname>RootDirectory=</varname>, instead of relative to the root
+ directory of the host (see above). When combining <literal>-</literal> and <literal>+</literal> on the same
+ path make sure to specify <literal>-</literal> first, and <literal>+</literal> second.</para>
+
+ <para>Note that using this setting will disconnect propagation of mounts from the service to the host
+ (propagation in the opposite direction continues to work). This means that this setting may not be used for
+ services which shall be able to install mount points in the main mount namespace. Note that the effect of these
+ settings may be undone by privileged processes. In order to set up an effective sandboxed environment for a
+ unit it is thus recommended to combine these settings with either
+ <varname>CapabilityBoundingSet=~CAP_SYS_ADMIN</varname> or
+ <varname>SystemCallFilter=~@mount</varname>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -999,7 +1005,11 @@
using <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> of
<filename>/dev/zero</filename> instead of using <constant>MAP_ANON</constant>. This setting is implied if
<varname>DynamicUser=</varname> is set. For this setting the same restrictions regarding mount propagation and
- privileges apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.</para></listitem>
+ privileges apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.
+ If turned on and if running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+ capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
+ is implied.
+ </para></listitem>
</varlistentry>
<varlistentry>
@@ -1090,9 +1100,35 @@
mechanism. Almost no services need to write to these at runtime; it is hence recommended to turn this on for
most services. For this setting the same restrictions regarding mount propagation and privileges apply as for
<varname>ReadOnlyPaths=</varname> and related calls, see above. Defaults to off.
- Note that this option does not prevent kernel tuning through IPC interfaces and external programs. However
- <varname>InaccessiblePaths=</varname> can be used to make some IPC file system objects
- inaccessible.</para></listitem>
+ If turned on and if running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+ capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
+ is implied. Note that this option does not prevent kernel tuning through IPC interfaces
+ and external programs. However <varname>InaccessiblePaths=</varname> can be used to
+ make some IPC file system objects inaccessible.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ProtectKernelModules=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If true, explicit module loading will
+ be denied. This allows to turn off module load and unload operations on modular
+ kernels. It is recommended to turn this on for most services that do not need special
+ file systems or extra kernel modules to work. Default to off. Enabling this option
+ removes <constant>CAP_SYS_MODULE</constant> from the capability bounding set for
+ the unit, and installs a system call filter to block module system calls,
+ also <filename>/usr/lib/modules</filename> is made inaccessible. For this
+ setting the same restrictions regarding mount propagation and privileges
+ apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.
+ Note that limited automatic module loading due to user configuration or kernel
+ mapping tables might still happen as side effect of requested user operations,
+ both privileged and unprivileged. To disable module auto-load feature please see
+ <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <constant>kernel.modules_disabled</constant> mechanism and
+ <filename>/proc/sys/kernel/modules_disabled</filename> documentation.
+ If turned on and if running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+ capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
+ is implied.
+ </para></listitem>
</varlistentry>
<varlistentry>
@@ -1237,7 +1273,7 @@
<listitem><para>Takes a boolean argument. If true, ensures that the service process and all its children can
never gain new privileges through <function>execve()</function> (e.g. via setuid or setgid bits, or filesystem
capabilities). This is the simplest and most effective way to ensure that a process and its children can never
- elevate privileges again. Defaults to false, but in the user manager instance certain settings force
+ elevate privileges again. Defaults to false, but certain settings force
<varname>NoNewPrivileges=yes</varname>, ignoring the value of this setting. This is the case when
<varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>,
<varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
@@ -1482,27 +1518,11 @@
<citerefentry><refentrytitle>setns</refentrytitle><manvolnum>2</manvolnum></citerefentry> system calls, taking
the specified flags parameters into account. Note that — if this option is used — in addition to restricting
creation and switching of the specified types of namespaces (or all of them, if true) access to the
- <function>setns()</function> system call with a zero flags parameter is prohibited.</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><varname>ProtectKernelModules=</varname></term>
-
- <listitem><para>Takes a boolean argument. If true, explicit module loading will
- be denied. This allows to turn off module load and unload operations on modular
- kernels. It is recommended to turn this on for most services that do not need special
- file systems or extra kernel modules to work. Default to off. Enabling this option
- removes <constant>CAP_SYS_MODULE</constant> from the capability bounding set for
- the unit, and installs a system call filter to block module system calls,
- also <filename>/usr/lib/modules</filename> is made inaccessible. For this
- setting the same restrictions regarding mount propagation and privileges
- apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.
- Note that limited automatic module loading due to user configuration or kernel
- mapping tables might still happen as side effect of requested user operations,
- both privileged and unprivileged. To disable module auto-load feature please see
- <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- <constant>kernel.modules_disabled</constant> mechanism and
- <filename>/proc/sys/kernel/modules_disabled</filename> documentation.</para></listitem>
+ <function>setns()</function> system call with a zero flags parameter is prohibited.
+ If running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+ capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
+ is implied.
+ </para></listitem>
</varlistentry>
<varlistentry>
@@ -1563,6 +1583,9 @@
that generate program code dynamically at runtime, such as JIT execution engines, or programs compiled making
use of the code "trampoline" feature of various C compilers. This option improves service security, as it makes
harder for software exploits to change running code dynamically.
+ If running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+ capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
+ is implied.
</para></listitem>
</varlistentry>
@@ -1573,7 +1596,10 @@
the unit are refused. This restricts access to realtime task scheduling policies such as
<constant>SCHED_FIFO</constant>, <constant>SCHED_RR</constant> or <constant>SCHED_DEADLINE</constant>. See
<citerefentry project='man-pages'><refentrytitle>sched</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details about
- these scheduling policies. Realtime scheduling policies may be used to monopolize CPU time for longer periods
+ these scheduling policies. If running in user mode, or in system mode, but
+ without the <constant>CAP_SYS_ADMIN</constant> capability
+ (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
+ is implied. Realtime scheduling policies may be used to monopolize CPU time for longer periods
of time, and may hence be used to lock up or otherwise trigger Denial-of-Service situations on the system. It
is hence recommended to restrict access to realtime scheduling to the few programs that actually require
them. Defaults to off.</para></listitem>
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 8edbe758d9..023e24eeb3 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -359,6 +359,20 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>AutoNegotiation=</varname></term>
+ <listitem>
+ <para>Enables or disables automatic negotiation of transmission parameters.
+ Autonegotiation is a procedure by which two connected ethernet devices choose
+ common transmission parameters, such as speed, duplex mode, and flow control.
+ Takes a boolean value. Unset by default, which means that the kernel default
+ will be used.</para>
+
+ <para>Note that if autonegotiation is enabled, speed and duplex settings are
+ read-only. If autonegotation is disabled, speed and duplex settings are writable
+ if the driver supports multiple link modes.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>WakeOnLan=</varname></term>
<listitem>
<para>The Wake-on-LAN policy to set for the device. The
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index b0f156f6df..68ff6f8f1c 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -241,6 +241,25 @@
</varlistentry>
<varlistentry>
+ <term><option>x-systemd.mount-timeout=</option></term>
+
+ <listitem><para>Configure how long systemd should wait for the
+ mount command to finish before giving up on an entry from
+ <filename>/etc/fstab</filename>. Specify a time in seconds or
+ explicitly append a unit such as <literal>s</literal>,
+ <literal>min</literal>, <literal>h</literal>,
+ <literal>ms</literal>.</para>
+
+ <para>Note that this option can only be used in
+ <filename>/etc/fstab</filename>, and will be
+ ignored when part of the <varname>Options=</varname>
+ setting in a unit file.</para>
+
+ <para>See <varname>TimeoutSec=</varname> below for
+ details.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><option>noauto</option></term>
<term><option>auto</option></term>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 2fb4907634..99283813fd 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -984,6 +984,13 @@
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>ListenPort=</varname></term>
+ <listitem>
+ <para>Allow setting custom port for the DHCP client to listen on.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 5c65957bda..3ba6ab34db 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -663,6 +663,12 @@
or signal is specified in
<varname>RestartForceExitStatus=</varname> (see below).</para>
+ <para>Note that service restart is subject to unit start rate
+ limiting configured with <varname>StartLimitIntervalSec=</varname>
+ and <varname>StartLimitBurst=</varname>, see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para>
+
<para>Setting this to <option>on-failure</option> is the
recommended choice for long-running services, in order to
increase reliability by attempting automatic recovery from
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 7c69ccdaf9..96da38d45e 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -395,7 +395,8 @@ int strv_env_replace(char ***l, char *p) {
for (f = *l; f && *f; f++)
if (env_match(*f, p)) {
- free_and_replace(*f, p);
+ free(*f);
+ *f = p;
strv_env_unset(f + 1, p);
return 0;
}
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index d6c1228463..dbe64a9a58 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -48,7 +48,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
/* Bail early if called after last value or with no input */
if (!*p)
- goto finish_force_terminate;
+ goto finish;
c = **p;
if (!separators)
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 4c013be608..a5ae5d9e79 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -1076,6 +1076,33 @@ typedef int32_t key_serial_t;
#define IFA_F_MCAUTOJOIN 0x400
#endif
+#ifndef HAVE_STRUCT_ETHTOOL_LINK_SETTINGS
+
+#define ETHTOOL_GLINKSETTINGS 0x0000004c /* Get ethtool_link_settings */
+#define ETHTOOL_SLINKSETTINGS 0x0000004d /* Set ethtool_link_settings */
+
+struct ethtool_link_settings {
+ __u32 cmd;
+ __u32 speed;
+ __u8 duplex;
+ __u8 port;
+ __u8 phy_address;
+ __u8 autoneg;
+ __u8 mdio_support;
+ __u8 eth_tp_mdix;
+ __u8 eth_tp_mdix_ctrl;
+ __s8 link_mode_masks_nwords;
+ __u32 reserved[8];
+ __u32 link_mode_masks[0];
+ /* layout of link_mode_masks fields:
+ * __u32 map_supported[link_mode_masks_nwords];
+ * __u32 map_advertising[link_mode_masks_nwords];
+ * __u32 map_lp_advertising[link_mode_masks_nwords];
+ */
+};
+
+#endif
+
#endif
#include "missing_syscall.h"
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 69b0f96183..d8d57381ad 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -496,7 +496,7 @@ static int userns_has_mapping(const char *name) {
f = fopen(name, "re");
if (!f) {
log_debug_errno(errno, "Failed to open %s: %m", name);
- return errno == -ENOENT ? false : -errno;
+ return errno == ENOENT ? false : -errno;
}
n = getline(&buf, &n_allocated, f);
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index d7bb0496a0..23c1b44573 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -781,7 +781,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RestrictNamespace", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index ccf7453d47..effc45db45 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -65,7 +65,7 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error
return r;
/* Access is granted to the job owner */
- if (!sd_bus_track_contains(j->clients, sd_bus_message_get_sender(message))) {
+ if (!sd_bus_track_contains(j->bus_track, sd_bus_message_get_sender(message))) {
/* And for everybody else consult PolicyKit */
r = bus_verify_manage_units_async(j->unit->manager, message, error);
@@ -80,9 +80,61 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error
return sd_bus_reply_method_return(message, NULL);
}
+int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ Job **list = NULL;
+ Job *j = userdata;
+ int r, i, n;
+
+ if (strstr(sd_bus_message_get_member(message), "After"))
+ n = job_get_after(j, &list);
+ else
+ n = job_get_before(j, &list);
+ if (n < 0)
+ return n;
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(usssoo)");
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < n; i ++) {
+ _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
+
+ job_path = job_dbus_path(list[i]);
+ if (!job_path)
+ return -ENOMEM;
+
+ unit_path = unit_dbus_path(list[i]->unit);
+ if (!unit_path)
+ return -ENOMEM;
+
+ r = sd_bus_message_append(reply, "(usssoo)",
+ list[i]->id,
+ list[i]->unit->id,
+ job_type_to_string(list[i]->type),
+ job_state_to_string(list[i]->state),
+ job_path,
+ unit_path);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
const sd_bus_vtable bus_job_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Cancel", NULL, NULL, bus_job_method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetAfter", NULL, "a(usssoo)", bus_job_method_get_waiting_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetBefore", NULL, "a(usssoo)", bus_job_method_get_waiting_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -143,7 +195,7 @@ void bus_job_send_change_signal(Job *j) {
j->in_dbus_queue = false;
}
- r = bus_foreach_bus(j->manager, j->clients, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal, j);
+ r = bus_foreach_bus(j->manager, j->bus_track, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal, j);
if (r < 0)
log_debug_errno(r, "Failed to send job change signal for %u: %m", j->id);
@@ -187,7 +239,70 @@ void bus_job_send_removed_signal(Job *j) {
if (!j->sent_dbus_new_signal)
bus_job_send_change_signal(j);
- r = bus_foreach_bus(j->manager, j->clients, send_removed_signal, j);
+ r = bus_foreach_bus(j->manager, j->bus_track, send_removed_signal, j);
if (r < 0)
log_debug_errno(r, "Failed to send job remove signal for %u: %m", j->id);
}
+
+static int bus_job_track_handler(sd_bus_track *t, void *userdata) {
+ Job *j = userdata;
+
+ assert(t);
+ assert(j);
+
+ j->bus_track = sd_bus_track_unref(j->bus_track); /* make sure we aren't called again */
+
+ /* Last client dropped off the bus, maybe we should GC this now? */
+ job_add_to_gc_queue(j);
+ return 0;
+}
+
+static int bus_job_allocate_bus_track(Job *j) {
+
+ assert(j);
+
+ if (j->bus_track)
+ return 0;
+
+ return sd_bus_track_new(j->unit->manager->api_bus, &j->bus_track, bus_job_track_handler, j);
+}
+
+int bus_job_coldplug_bus_track(Job *j) {
+ int r = 0;
+ _cleanup_strv_free_ char **deserialized_clients = NULL;
+
+ assert(j);
+
+ deserialized_clients = j->deserialized_clients;
+ j->deserialized_clients = NULL;
+
+ if (strv_isempty(deserialized_clients))
+ return 0;
+
+ if (!j->manager->api_bus)
+ return 0;
+
+ r = bus_job_allocate_bus_track(j);
+ if (r < 0)
+ return r;
+
+ return bus_track_add_name_many(j->bus_track, deserialized_clients);
+}
+
+int bus_job_track_sender(Job *j, sd_bus_message *m) {
+ int r;
+
+ assert(j);
+ assert(m);
+
+ if (sd_bus_message_get_bus(m) != j->unit->manager->api_bus) {
+ j->ref_by_private_bus = true;
+ return 0;
+ }
+
+ r = bus_job_allocate_bus_track(j);
+ if (r < 0)
+ return r;
+
+ return sd_bus_track_add_sender(j->bus_track, m);
+}
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
index 024d06719e..a4366a0720 100644
--- a/src/core/dbus-job.h
+++ b/src/core/dbus-job.h
@@ -26,6 +26,10 @@
extern const sd_bus_vtable bus_job_vtable[];
int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error);
+int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error);
void bus_job_send_change_signal(Job *j);
void bus_job_send_removed_signal(Job *j);
+
+int bus_job_coldplug_bus_track(Job *j);
+int bus_job_track_sender(Job *j, sd_bus_message *m);
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 5a7922a249..9af49dd1bc 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2285,6 +2285,26 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s
return sd_bus_send(NULL, reply, NULL);
}
+static int method_get_job_waiting(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ uint32_t id;
+ Job *j;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "u", &id);
+ if (r < 0)
+ return r;
+
+ j = manager_get_job(m, id);
+ if (!j)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
+
+ return bus_job_method_get_waiting_jobs(message, j, error);
+}
+
const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_VTABLE_START(0),
@@ -2390,6 +2410,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetJobAfter", "u", "a(usssoo)", method_get_job_waiting, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetJobBefore", "u", "a(usssoo)", method_get_job_waiting, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index b6cb6e1350..2adc1d9288 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -22,6 +22,7 @@
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "cgroup-util.h"
+#include "dbus-job.h"
#include "dbus-unit.h"
#include "dbus.h"
#include "fd-util.h"
@@ -1223,17 +1224,9 @@ int bus_unit_queue_job(
if (r < 0)
return r;
- if (sd_bus_message_get_bus(message) == u->manager->api_bus) {
- if (!j->clients) {
- r = sd_bus_track_new(sd_bus_message_get_bus(message), &j->clients, NULL, NULL);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_track_add_sender(j->clients, message);
- if (r < 0)
- return r;
- }
+ r = bus_job_track_sender(j, message);
+ if (r < 0)
+ return r;
path = job_dbus_path(j);
if (!path)
@@ -1507,7 +1500,7 @@ int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id);
}
-static int bus_track_handler(sd_bus_track *t, void *userdata) {
+static int bus_unit_track_handler(sd_bus_track *t, void *userdata) {
Unit *u = userdata;
assert(t);
@@ -1519,7 +1512,7 @@ static int bus_track_handler(sd_bus_track *t, void *userdata) {
return 0;
}
-static int allocate_bus_track(Unit *u) {
+static int bus_unit_allocate_bus_track(Unit *u) {
int r;
assert(u);
@@ -1527,7 +1520,7 @@ static int allocate_bus_track(Unit *u) {
if (u->bus_track)
return 0;
- r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_track_handler, u);
+ r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_unit_track_handler, u);
if (r < 0)
return r;
@@ -1545,7 +1538,7 @@ int bus_unit_track_add_name(Unit *u, const char *name) {
assert(u);
- r = allocate_bus_track(u);
+ r = bus_unit_allocate_bus_track(u);
if (r < 0)
return r;
@@ -1557,7 +1550,7 @@ int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
assert(u);
- r = allocate_bus_track(u);
+ r = bus_unit_allocate_bus_track(u);
if (r < 0)
return r;
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 070974fe66..07ab21f199 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -1054,8 +1054,8 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
m->subscribed = sd_bus_track_unref(m->subscribed);
HASHMAP_FOREACH(j, m->jobs, i)
- if (j->clients && sd_bus_track_get_bus(j->clients) == *bus)
- j->clients = sd_bus_track_unref(j->clients);
+ if (j->bus_track && sd_bus_track_get_bus(j->bus_track) == *bus)
+ j->bus_track = sd_bus_track_unref(j->bus_track);
/* Get rid of queued message on this bus */
if (m->queued_message && sd_bus_message_get_bus(m->queued_message) == *bus)
@@ -1185,7 +1185,6 @@ void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) {
}
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) {
- char **i;
int r = 0;
assert(m);
@@ -1207,16 +1206,7 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) {
if (r < 0)
return r;
- r = 0;
- STRV_FOREACH(i, l) {
- int k;
-
- k = sd_bus_track_add_name(*t, *i);
- if (k < 0)
- r = k;
- }
-
- return r;
+ return bus_track_add_name_many(*t, l);
}
int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
diff --git a/src/core/device.c b/src/core/device.c
index c572a6737c..074e93ffe2 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -831,6 +831,8 @@ const UnitVTable device_vtable = {
"Device\0"
"Install\0",
+ .gc_jobs = true,
+
.init = device_init,
.done = device_done,
.load = unit_load_fragment_and_dropin_optional,
diff --git a/src/core/execute.c b/src/core/execute.c
index 084eca334c..07ab067c05 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2276,7 +2276,8 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
if (have_effective_cap(CAP_SYS_ADMIN)) /* if we are privileged, we don't need NNP */
return false;
- return context_has_address_families(c) || /* we need NNP if we have any form of seccomp and are unprivileged */
+ /* We need NNP if we have any form of seccomp and are unprivileged */
+ return context_has_address_families(c) ||
c->memory_deny_write_execute ||
c->restrict_realtime ||
exec_context_restrict_namespaces_set(c) ||
diff --git a/src/core/execute.h b/src/core/execute.h
index cd7cbcc5ab..951c8f4da3 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -216,7 +216,6 @@ struct ExecContext {
bool nice_set:1;
bool ioprio_set:1;
bool cpu_sched_set:1;
- bool no_new_privileges_set:1;
};
static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
diff --git a/src/core/job.c b/src/core/job.c
index ac6910a906..2ba4c78096 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -90,9 +90,12 @@ void job_free(Job *j) {
if (j->in_dbus_queue)
LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
+ if (j->in_gc_queue)
+ LIST_REMOVE(gc_queue, j->manager->gc_job_queue, j);
+
sd_event_source_unref(j->timer_event_source);
- sd_bus_track_unref(j->clients);
+ sd_bus_track_unref(j->bus_track);
strv_free(j->deserialized_clients);
free(j);
@@ -226,6 +229,9 @@ Job* job_install(Job *j) {
log_unit_debug(j->unit,
"Installed new job %s/%s as %u",
j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
+
+ job_add_to_gc_queue(j);
+
return j;
}
@@ -267,7 +273,8 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool
* this means the 'anchor' job (i.e. the one the user
* explicitly asked for) is the requester. */
- if (!(l = new0(JobDependency, 1)))
+ l = new0(JobDependency, 1);
+ if (!l)
return NULL;
l->subject = subject;
@@ -457,9 +464,7 @@ static bool job_is_runnable(Job *j) {
if (j->type == JOB_NOP)
return true;
- if (j->type == JOB_START ||
- j->type == JOB_VERIFY_ACTIVE ||
- j->type == JOB_RELOAD) {
+ if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
/* Immediate result is that the job is or might be
* started. In this case let's wait for the
@@ -476,8 +481,7 @@ static bool job_is_runnable(Job *j) {
SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
if (other->job &&
- (other->job->type == JOB_STOP ||
- other->job->type == JOB_RESTART))
+ IN_SET(other->job->type, JOB_STOP, JOB_RESTART))
return false;
/* This means that for a service a and a service b where b
@@ -641,6 +645,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
[JOB_DEPENDENCY] = "Dependency failed for %s.",
[JOB_ASSERT] = "Assertion failed for %s.",
[JOB_UNSUPPORTED] = "Starting of %s not supported.",
+ [JOB_COLLECTED] = "Unecessary job for %s was removed.",
};
static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Stopped %s.",
@@ -700,6 +705,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
[JOB_SKIPPED] = { ANSI_HIGHLIGHT, " INFO " },
[JOB_ASSERT] = { ANSI_HIGHLIGHT_YELLOW, "ASSERT" },
[JOB_UNSUPPORTED] = { ANSI_HIGHLIGHT_YELLOW, "UNSUPP" },
+ [JOB_COLLECTED] = { ANSI_HIGHLIGHT, " INFO " },
};
const char *format;
@@ -751,6 +757,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
[JOB_INVALID] = LOG_INFO,
[JOB_ASSERT] = LOG_WARNING,
[JOB_UNSUPPORTED] = LOG_WARNING,
+ [JOB_COLLECTED] = LOG_INFO,
};
assert(u);
@@ -862,6 +869,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
job_set_state(j, JOB_WAITING);
job_add_to_run_queue(j);
+ job_add_to_gc_queue(j);
goto finish;
}
@@ -905,11 +913,15 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
finish:
/* Try to start the next jobs that can be started */
SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
- if (other->job)
+ if (other->job) {
job_add_to_run_queue(other->job);
+ job_add_to_gc_queue(other->job);
+ }
SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
- if (other->job)
+ if (other->job) {
job_add_to_run_queue(other->job);
+ job_add_to_gc_queue(other->job);
+ }
manager_check_finished(u->manager);
@@ -1012,7 +1024,7 @@ int job_serialize(Job *j, FILE *f) {
if (j->begin_usec > 0)
fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
- bus_track_serialize(j->clients, f, "subscribed");
+ bus_track_serialize(j->bus_track, f, "subscribed");
/* End marker */
fputc('\n', f);
@@ -1123,12 +1135,14 @@ int job_coldplug(Job *j) {
/* After deserialization is complete and the bus connection
* set up again, let's start watching our subscribers again */
- (void) bus_track_coldplug(j->manager, &j->clients, false, j->deserialized_clients);
- j->deserialized_clients = strv_free(j->deserialized_clients);
+ (void) bus_job_coldplug_bus_track(j);
if (j->state == JOB_WAITING)
job_add_to_run_queue(j);
+ /* Maybe due to new dependencies we don't actually need this job anymore? */
+ job_add_to_gc_queue(j);
+
if (j->begin_usec == 0 || j->unit->job_timeout == USEC_INFINITY)
return 0;
@@ -1203,9 +1217,225 @@ int job_get_timeout(Job *j, usec_t *timeout) {
return 1;
}
+bool job_check_gc(Job *j) {
+ Unit *other;
+ Iterator i;
+
+ assert(j);
+
+ /* Checks whether this job should be GC'ed away. We only do this for jobs of units that have no effect on their
+ * own and just track external state. For now the only unit type that qualifies for this are .device units. */
+
+ if (!UNIT_VTABLE(j->unit)->gc_jobs)
+ return true;
+
+ if (sd_bus_track_count(j->bus_track) > 0)
+ return true;
+
+ /* FIXME: So this is a bit ugly: for now we don't properly track references made via private bus connections
+ * (because it's nasty, as sd_bus_track doesn't apply to it). We simply remember that the job was once
+ * referenced by one, and reset this whenever we notice that no private bus connections are around. This means
+ * the GC is a bit too conservative when it comes to jobs created by private bus connections. */
+ if (j->ref_by_private_bus) {
+ if (set_isempty(j->unit->manager->private_buses))
+ j->ref_by_private_bus = false;
+ else
+ return true;
+ }
+
+ if (j->type == JOB_NOP)
+ return true;
+
+ /* If a job is ordered after ours, and is to be started, then it needs to wait for us, regardless if we stop or
+ * start, hence let's not GC in that case. */
+ SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ if (!other->job)
+ continue;
+
+ if (other->job->ignore_order)
+ continue;
+
+ if (IN_SET(other->job->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD))
+ return true;
+ }
+
+ /* If we are going down, but something else is orederd After= us, then it needs to wait for us */
+ if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) {
+
+ SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ if (!other->job)
+ continue;
+
+ if (other->job->ignore_order)
+ continue;
+
+ return true;
+ }
+ }
+
+ /* The logic above is kinda the inverse of the job_is_runnable() logic. Specifically, if the job "we" is
+ * ordered before the job "other":
+ *
+ * we start + other start → stay
+ * we start + other stop → gc
+ * we stop + other start → stay
+ * we stop + other stop → gc
+ *
+ * "we" are ordered after "other":
+ *
+ * we start + other start → gc
+ * we start + other stop → gc
+ * we stop + other start → stay
+ * we stop + other stop → stay
+ *
+ */
+
+ return false;
+}
+
+void job_add_to_gc_queue(Job *j) {
+ assert(j);
+
+ if (j->in_gc_queue)
+ return;
+
+ if (job_check_gc(j))
+ return;
+
+ LIST_PREPEND(gc_queue, j->unit->manager->gc_job_queue, j);
+ j->in_gc_queue = true;
+}
+
+static int job_compare(const void *a, const void *b) {
+ Job *x = *(Job**) a, *y = *(Job**) b;
+
+ if (x->id < y->id)
+ return -1;
+ if (x->id > y->id)
+ return 1;
+
+ return 0;
+}
+
+static size_t sort_job_list(Job **list, size_t n) {
+ Job *previous = NULL;
+ size_t a, b;
+
+ /* Order by numeric IDs */
+ qsort_safe(list, n, sizeof(Job*), job_compare);
+
+ /* Filter out duplicates */
+ for (a = 0, b = 0; a < n; a++) {
+
+ if (previous == list[a])
+ continue;
+
+ previous = list[b++] = list[a];
+ }
+
+ return b;
+}
+
+int job_get_before(Job *j, Job*** ret) {
+ _cleanup_free_ Job** list = NULL;
+ size_t n = 0, n_allocated = 0;
+ Unit *other = NULL;
+ Iterator i;
+
+ /* Returns a list of all pending jobs that need to finish before this job may be started. */
+
+ assert(j);
+ assert(ret);
+
+ if (j->ignore_order) {
+ *ret = NULL;
+ return 0;
+ }
+
+ if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
+
+ SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ if (!other->job)
+ continue;
+
+ if (!GREEDY_REALLOC(list, n_allocated, n+1))
+ return -ENOMEM;
+ list[n++] = other->job;
+ }
+ }
+
+ SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ if (!other->job)
+ continue;
+
+ if (!IN_SET(other->job->type, JOB_STOP, JOB_RESTART))
+ continue;
+
+ if (!GREEDY_REALLOC(list, n_allocated, n+1))
+ return -ENOMEM;
+ list[n++] = other->job;
+ }
+
+ n = sort_job_list(list, n);
+
+ *ret = list;
+ list = NULL;
+
+ return (int) n;
+}
+
+int job_get_after(Job *j, Job*** ret) {
+ _cleanup_free_ Job** list = NULL;
+ size_t n = 0, n_allocated = 0;
+ Unit *other = NULL;
+ Iterator i;
+
+ assert(j);
+ assert(ret);
+
+ /* Returns a list of all pending jobs that are waiting for this job to finish. */
+
+ SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ if (!other->job)
+ continue;
+
+ if (other->job->ignore_order)
+ continue;
+
+ if (!IN_SET(other->job->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD))
+ continue;
+
+ if (!GREEDY_REALLOC(list, n_allocated, n+1))
+ return -ENOMEM;
+ list[n++] = other->job;
+ }
+
+ if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) {
+
+ SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ if (!other->job)
+ continue;
+
+ if (other->job->ignore_order)
+ continue;
+
+ if (!GREEDY_REALLOC(list, n_allocated, n+1))
+ return -ENOMEM;
+ list[n++] = other->job;
+ }
+ }
+
+ n = sort_job_list(list, n);
+
+ *ret = list;
+ list = NULL;
+
+ return (int) n;
+}
+
static const char* const job_state_table[_JOB_STATE_MAX] = {
[JOB_WAITING] = "waiting",
- [JOB_RUNNING] = "running"
+ [JOB_RUNNING] = "running",
};
DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
@@ -1246,6 +1476,7 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = {
[JOB_INVALID] = "invalid",
[JOB_ASSERT] = "assert",
[JOB_UNSUPPORTED] = "unsupported",
+ [JOB_COLLECTED] = "collected",
};
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/core/job.h b/src/core/job.h
index 85368f0d30..bea743f462 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -107,6 +107,7 @@ enum JobResult {
JOB_INVALID, /* JOB_RELOAD of inactive unit */
JOB_ASSERT, /* Couldn't start a unit, because an assert didn't hold */
JOB_UNSUPPORTED, /* Couldn't start a unit, because the unit type is not supported on the system */
+ JOB_COLLECTED, /* Job was garbage collected, since nothing needed it anymore */
_JOB_RESULT_MAX,
_JOB_RESULT_INVALID = -1
};
@@ -122,8 +123,8 @@ struct JobDependency {
LIST_FIELDS(JobDependency, subject);
LIST_FIELDS(JobDependency, object);
- bool matters;
- bool conflicts;
+ bool matters:1;
+ bool conflicts:1;
};
struct Job {
@@ -133,6 +134,7 @@ struct Job {
LIST_FIELDS(Job, transaction);
LIST_FIELDS(Job, run_queue);
LIST_FIELDS(Job, dbus_queue);
+ LIST_FIELDS(Job, gc_queue);
LIST_HEAD(JobDependency, subject_list);
LIST_HEAD(JobDependency, object_list);
@@ -156,7 +158,7 @@ struct Job {
*
* There can be more than one client, because of job merging.
*/
- sd_bus_track *clients;
+ sd_bus_track *bus_track;
char **deserialized_clients;
JobResult result;
@@ -168,6 +170,8 @@ struct Job {
bool sent_dbus_new_signal:1;
bool ignore_order:1;
bool irreversible:1;
+ bool in_gc_queue:1;
+ bool ref_by_private_bus:1;
};
Job* job_new(Unit *unit, JobType type);
@@ -227,6 +231,12 @@ void job_shutdown_magic(Job *j);
int job_get_timeout(Job *j, usec_t *timeout) _pure_;
+bool job_check_gc(Job *j);
+void job_add_to_gc_queue(Job *j);
+
+int job_get_before(Job *j, Job*** ret);
+int job_get_after(Job *j, Job*** ret);
+
const char* job_type_to_string(JobType t) _const_;
JobType job_type_from_string(const char *s) _pure_;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index cb2f384f47..f4ef5a0140 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -57,7 +57,7 @@ m4_ifdef(`HAVE_SECCOMP',
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
-$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context.restrict_namespaces)
+$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)',
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 52079980d8..970eed27c1 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3896,7 +3896,6 @@ int config_parse_no_new_privileges(
}
c->no_new_privileges = k;
- c->no_new_privileges_set = true;
return 0;
}
diff --git a/src/core/manager.c b/src/core/manager.c
index b49e3b593a..1f663d3c1d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -987,10 +987,9 @@ good:
unit_gc_mark_good(u, gc_marker);
}
-static unsigned manager_dispatch_gc_queue(Manager *m) {
+static unsigned manager_dispatch_gc_unit_queue(Manager *m) {
+ unsigned n = 0, gc_marker;
Unit *u;
- unsigned n = 0;
- unsigned gc_marker;
assert(m);
@@ -1002,12 +1001,12 @@ static unsigned manager_dispatch_gc_queue(Manager *m) {
gc_marker = m->gc_marker;
- while ((u = m->gc_queue)) {
+ while ((u = m->gc_unit_queue)) {
assert(u->in_gc_queue);
unit_gc_sweep(u, gc_marker);
- LIST_REMOVE(gc_queue, m->gc_queue, u);
+ LIST_REMOVE(gc_queue, m->gc_unit_queue, u);
u->in_gc_queue = false;
n++;
@@ -1021,7 +1020,29 @@ static unsigned manager_dispatch_gc_queue(Manager *m) {
}
}
- m->n_in_gc_queue = 0;
+ return n;
+}
+
+static unsigned manager_dispatch_gc_job_queue(Manager *m) {
+ unsigned n = 0;
+ Job *j;
+
+ assert(m);
+
+ while ((j = m->gc_job_queue)) {
+ assert(j->in_gc_queue);
+
+ LIST_REMOVE(gc_queue, m->gc_job_queue, j);
+ j->in_gc_queue = false;
+
+ n++;
+
+ if (job_check_gc(j))
+ continue;
+
+ log_unit_debug(j->unit, "Collecting job.");
+ (void) job_finish_and_invalidate(j, JOB_COLLECTED, false, false);
+ }
return n;
}
@@ -1041,7 +1062,8 @@ static void manager_clear_jobs_and_units(Manager *m) {
assert(!m->dbus_unit_queue);
assert(!m->dbus_job_queue);
assert(!m->cleanup_queue);
- assert(!m->gc_queue);
+ assert(!m->gc_unit_queue);
+ assert(!m->gc_job_queue);
assert(hashmap_isempty(m->jobs));
assert(hashmap_isempty(m->units));
@@ -2234,7 +2256,10 @@ int manager_loop(Manager *m) {
if (manager_dispatch_load_queue(m) > 0)
continue;
- if (manager_dispatch_gc_queue(m) > 0)
+ if (manager_dispatch_gc_job_queue(m) > 0)
+ continue;
+
+ if (manager_dispatch_gc_unit_queue(m) > 0)
continue;
if (manager_dispatch_cleanup_queue(m) > 0)
diff --git a/src/core/manager.h b/src/core/manager.h
index 4f17f1eea5..4a9a37caff 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -104,8 +104,9 @@ struct Manager {
/* Units to remove */
LIST_HEAD(Unit, cleanup_queue);
- /* Units to check when doing GC */
- LIST_HEAD(Unit, gc_queue);
+ /* Units and jobs to check when doing GC */
+ LIST_HEAD(Unit, gc_unit_queue);
+ LIST_HEAD(Job, gc_job_queue);
/* Units that should be realized */
LIST_HEAD(Unit, cgroup_queue);
@@ -229,7 +230,6 @@ struct Manager {
int pin_cgroupfs_fd;
int gc_marker;
- unsigned n_in_gc_queue;
/* Flags */
ManagerExitCode exit_code:5;
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 308e4d768e..e9ad26bfc3 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -58,17 +58,13 @@ typedef enum MountMode {
} MountMode;
typedef struct BindMount {
- char *path;
- MountMode mode;
- bool ignore; /* Ignore if path does not exist */
+ const char *path_const; /* Memory allocated on stack or static */
+ MountMode mode:6;
+ bool ignore:1; /* Ignore if path does not exist? */
+ bool has_prefix:1; /* Already is prefixed by the root dir? */
+ char *path_malloc; /* Use this instead of 'path' if we had to allocate memory */
} BindMount;
-typedef struct TargetMount {
- const char *path;
- MountMode mode;
- bool ignore; /* Ignore if path does not exist */
-} TargetMount;
-
/*
* The following Protect tables are to protect paths and mark some of them
* READONLY, in case a path is covered by an option from another table, then
@@ -78,62 +74,62 @@ typedef struct TargetMount {
*/
/* ProtectKernelTunables= option and the related filesystem APIs */
-static const TargetMount protect_kernel_tunables_table[] = {
- { "/proc/sys", READONLY, false },
- { "/proc/sysrq-trigger", READONLY, true },
- { "/proc/latency_stats", READONLY, true },
- { "/proc/mtrr", READONLY, true },
- { "/proc/apm", READONLY, true },
- { "/proc/acpi", READONLY, true },
- { "/proc/timer_stats", READONLY, true },
- { "/proc/asound", READONLY, true },
- { "/proc/bus", READONLY, true },
- { "/proc/fs", READONLY, true },
- { "/proc/irq", READONLY, true },
- { "/sys", READONLY, false },
- { "/sys/kernel/debug", READONLY, true },
- { "/sys/kernel/tracing", READONLY, true },
- { "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
+static const BindMount protect_kernel_tunables_table[] = {
+ { "/proc/sys", READONLY, false },
+ { "/proc/sysrq-trigger", READONLY, true },
+ { "/proc/latency_stats", READONLY, true },
+ { "/proc/mtrr", READONLY, true },
+ { "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
+ { "/proc/acpi", READONLY, true },
+ { "/proc/timer_stats", READONLY, true },
+ { "/proc/asound", READONLY, true },
+ { "/proc/bus", READONLY, true },
+ { "/proc/fs", READONLY, true },
+ { "/proc/irq", READONLY, true },
+ { "/sys", READONLY, false },
+ { "/sys/kernel/debug", READONLY, true },
+ { "/sys/kernel/tracing", READONLY, true },
+ { "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
};
/* ProtectKernelModules= option */
-static const TargetMount protect_kernel_modules_table[] = {
+static const BindMount protect_kernel_modules_table[] = {
#ifdef HAVE_SPLIT_USR
- { "/lib/modules", INACCESSIBLE, true },
+ { "/lib/modules", INACCESSIBLE, true },
#endif
- { "/usr/lib/modules", INACCESSIBLE, true },
+ { "/usr/lib/modules", INACCESSIBLE, true },
};
/*
* ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
* system should be protected by ProtectSystem=
*/
-static const TargetMount protect_home_read_only_table[] = {
- { "/home", READONLY, true },
- { "/run/user", READONLY, true },
- { "/root", READONLY, true },
+static const BindMount protect_home_read_only_table[] = {
+ { "/home", READONLY, true },
+ { "/run/user", READONLY, true },
+ { "/root", READONLY, true },
};
/* ProtectHome=yes table */
-static const TargetMount protect_home_yes_table[] = {
- { "/home", INACCESSIBLE, true },
- { "/run/user", INACCESSIBLE, true },
- { "/root", INACCESSIBLE, true },
+static const BindMount protect_home_yes_table[] = {
+ { "/home", INACCESSIBLE, true },
+ { "/run/user", INACCESSIBLE, true },
+ { "/root", INACCESSIBLE, true },
};
/* ProtectSystem=yes table */
-static const TargetMount protect_system_yes_table[] = {
- { "/usr", READONLY, false },
- { "/boot", READONLY, true },
- { "/efi", READONLY, true },
+static const BindMount protect_system_yes_table[] = {
+ { "/usr", READONLY, false },
+ { "/boot", READONLY, true },
+ { "/efi", READONLY, true },
};
/* ProtectSystem=full includes ProtectSystem=yes */
-static const TargetMount protect_system_full_table[] = {
- { "/usr", READONLY, false },
- { "/boot", READONLY, true },
- { "/efi", READONLY, true },
- { "/etc", READONLY, false },
+static const BindMount protect_system_full_table[] = {
+ { "/usr", READONLY, false },
+ { "/boot", READONLY, true },
+ { "/efi", READONLY, true },
+ { "/etc", READONLY, false },
};
/*
@@ -144,7 +140,7 @@ static const TargetMount protect_system_full_table[] = {
* (And of course /home and friends are also left writable, as ProtectHome=
* shall manage those, orthogonally).
*/
-static const TargetMount protect_system_strict_table[] = {
+static const BindMount protect_system_strict_table[] = {
{ "/", READONLY, false },
{ "/proc", READWRITE, false }, /* ProtectKernelTunables= */
{ "/sys", READWRITE, false }, /* ProtectKernelTunables= */
@@ -154,154 +150,107 @@ static const TargetMount protect_system_strict_table[] = {
{ "/root", READWRITE, true }, /* ProtectHome= */
};
-static void set_bind_mount(BindMount *p, char *path, MountMode mode, bool ignore) {
- p->path = path;
- p->mode = mode;
- p->ignore = ignore;
-}
-
-static int append_one_mount(BindMount **p, const char *root_directory,
- const char *path, MountMode mode, bool ignore) {
- char *lpath;
+static const char *bind_mount_path(const BindMount *p) {
assert(p);
- lpath = prefix_root(root_directory, path);
- if (!lpath)
- return -ENOMEM;
+ /* Returns the path of this bind mount. If the malloc()-allocated ->path_buffer field is set we return that,
+ * otherwise the stack/static ->path field is returned. */
- set_bind_mount((*p)++, lpath, mode, ignore);
- return 0;
+ return p->path_malloc ?: p->path_const;
}
-static int append_mounts(BindMount **p, char **strv, MountMode mode) {
+static int append_access_mounts(BindMount **p, char **strv, MountMode mode) {
char **i;
assert(p);
+ /* Adds a list of user-supplied READWRITE/READONLY/INACCESSIBLE entries */
+
STRV_FOREACH(i, strv) {
- bool ignore = false;
- char *path;
+ bool ignore = false, needs_prefix = false;
+ const char *e = *i;
- if (IN_SET(mode, INACCESSIBLE, READONLY, READWRITE) && startswith(*i, "-")) {
- (*i)++;
+ /* Look for any prefixes */
+ if (startswith(e, "-")) {
+ e++;
ignore = true;
}
+ if (startswith(e, "+")) {
+ e++;
+ needs_prefix = true;
+ }
- if (!path_is_absolute(*i))
+ if (!path_is_absolute(e))
return -EINVAL;
- path = strdup(*i);
- if (!path)
- return -ENOMEM;
-
- set_bind_mount((*p)++, path, mode, ignore);
+ *((*p)++) = (BindMount) {
+ .path_const = e,
+ .mode = mode,
+ .ignore = ignore,
+ .has_prefix = !needs_prefix,
+ };
}
return 0;
}
-static int append_target_mounts(BindMount **p, const char *root_directory,
- const TargetMount *mounts, const size_t size, bool ignore_protect) {
+static int append_static_mounts(BindMount **p, const BindMount *mounts, unsigned n, bool ignore_protect) {
unsigned i;
assert(p);
assert(mounts);
- for (i = 0; i < size; i++) {
- bool ignore;
- /*
- * Here we assume that the ignore field is set during
- * declaration we do not support "-" at the beginning.
- */
- const TargetMount *m = &mounts[i];
- char *path;
-
- path = prefix_root(root_directory, m->path);
- if (!path)
- return -ENOMEM;
-
- if (!path_is_absolute(path))
- return -EINVAL;
-
- /*
- * Ignore paths if they are not present. First we use our
- * static tables otherwise fallback to Unit context.
- */
- ignore = m->ignore || ignore_protect;
+ /* Adds a list of static pre-defined entries */
- set_bind_mount((*p)++, path, m->mode, ignore);
- }
+ for (i = 0; i < n; i++)
+ *((*p)++) = (BindMount) {
+ .path_const = bind_mount_path(mounts+i),
+ .mode = mounts[i].mode,
+ .ignore = mounts[i].ignore || ignore_protect,
+ };
return 0;
}
-static int append_protect_kernel_tunables(BindMount **p, const char *root_directory, bool ignore_protect) {
+static int append_protect_home(BindMount **p, ProtectHome protect_home, bool ignore_protect) {
assert(p);
- return append_target_mounts(p, root_directory, protect_kernel_tunables_table,
- ELEMENTSOF(protect_kernel_tunables_table), ignore_protect);
-}
-
-static int append_protect_kernel_modules(BindMount **p, const char *root_directory, bool ignore_protect) {
- assert(p);
-
- return append_target_mounts(p, root_directory, protect_kernel_modules_table,
- ELEMENTSOF(protect_kernel_modules_table), ignore_protect);
-}
-
-static int append_protect_home(BindMount **p, const char *root_directory, ProtectHome protect_home, bool ignore_protect) {
- int r = 0;
-
- assert(p);
+ switch (protect_home) {
- if (protect_home == PROTECT_HOME_NO)
+ case PROTECT_HOME_NO:
return 0;
- switch (protect_home) {
case PROTECT_HOME_READ_ONLY:
- r = append_target_mounts(p, root_directory, protect_home_read_only_table,
- ELEMENTSOF(protect_home_read_only_table),
- ignore_protect);
- break;
+ return append_static_mounts(p, protect_home_read_only_table, ELEMENTSOF(protect_home_read_only_table), ignore_protect);
+
case PROTECT_HOME_YES:
- r = append_target_mounts(p, root_directory, protect_home_yes_table,
- ELEMENTSOF(protect_home_yes_table), ignore_protect);
- break;
+ return append_static_mounts(p, protect_home_yes_table, ELEMENTSOF(protect_home_yes_table), ignore_protect);
+
default:
- r = -EINVAL;
- break;
+ assert_not_reached("Unexpected ProtectHome= value");
}
-
- return r;
}
-static int append_protect_system(BindMount **p, const char *root_directory, ProtectSystem protect_system, bool ignore_protect) {
- int r = 0;
-
+static int append_protect_system(BindMount **p, ProtectSystem protect_system, bool ignore_protect) {
assert(p);
- if (protect_system == PROTECT_SYSTEM_NO)
+ switch (protect_system) {
+
+ case PROTECT_SYSTEM_NO:
return 0;
- switch (protect_system) {
case PROTECT_SYSTEM_STRICT:
- r = append_target_mounts(p, root_directory, protect_system_strict_table,
- ELEMENTSOF(protect_system_strict_table), ignore_protect);
- break;
+ return append_static_mounts(p, protect_system_strict_table, ELEMENTSOF(protect_system_strict_table), ignore_protect);
+
case PROTECT_SYSTEM_YES:
- r = append_target_mounts(p, root_directory, protect_system_yes_table,
- ELEMENTSOF(protect_system_yes_table), ignore_protect);
- break;
+ return append_static_mounts(p, protect_system_yes_table, ELEMENTSOF(protect_system_yes_table), ignore_protect);
+
case PROTECT_SYSTEM_FULL:
- r = append_target_mounts(p, root_directory, protect_system_full_table,
- ELEMENTSOF(protect_system_full_table), ignore_protect);
- break;
+ return append_static_mounts(p, protect_system_full_table, ELEMENTSOF(protect_system_full_table), ignore_protect);
+
default:
- r = -EINVAL;
- break;
+ assert_not_reached("Unexpected ProtectSystem= value");
}
-
- return r;
}
static int mount_path_compare(const void *a, const void *b) {
@@ -309,7 +258,7 @@ static int mount_path_compare(const void *a, const void *b) {
int d;
/* If the paths are not equal, then order prefixes first */
- d = path_compare(p->path, q->path);
+ d = path_compare(bind_mount_path(p), bind_mount_path(q));
if (d != 0)
return d;
@@ -323,6 +272,34 @@ static int mount_path_compare(const void *a, const void *b) {
return 0;
}
+static int prefix_where_needed(BindMount *m, unsigned n, const char *root_directory) {
+ unsigned i;
+
+ /* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
+ * that. */
+
+ if (!root_directory)
+ return 0;
+
+ for (i = 0; i < n; i++) {
+ char *s;
+
+ if (m[i].has_prefix)
+ continue;
+
+ s = prefix_root(root_directory, bind_mount_path(m+i));
+ if (!s)
+ return -ENOMEM;
+
+ free(m[i].path_malloc);
+ m[i].path_malloc = s;
+
+ m[i].has_prefix = true;
+ }
+
+ return 0;
+}
+
static void drop_duplicates(BindMount *m, unsigned *n) {
BindMount *f, *t, *previous;
@@ -331,13 +308,13 @@ static void drop_duplicates(BindMount *m, unsigned *n) {
/* Drops duplicate entries. Expects that the array is properly ordered already. */
- for (f = m, t = m, previous = NULL; f < m+*n; f++) {
+ for (f = m, t = m, previous = NULL; f < m + *n; f++) {
/* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
* above. */
- if (previous && path_equal(f->path, previous->path)) {
- log_debug("%s is duplicate.", f->path);
- f->path = mfree(f->path);
+ if (previous && path_equal(bind_mount_path(f), bind_mount_path(previous))) {
+ log_debug("%s is duplicate.", bind_mount_path(f));
+ f->path_malloc = mfree(f->path_malloc);
continue;
}
@@ -359,17 +336,17 @@ static void drop_inaccessible(BindMount *m, unsigned *n) {
/* Drops all entries obstructed by another entry further up the tree. Expects that the array is properly
* ordered already. */
- for (f = m, t = m; f < m+*n; f++) {
+ for (f = m, t = m; f < m + *n; f++) {
/* If we found a path set for INACCESSIBLE earlier, and this entry has it as prefix we should drop
* it, as inaccessible paths really should drop the entire subtree. */
- if (clear && path_startswith(f->path, clear)) {
- log_debug("%s is masked by %s.", f->path, clear);
- f->path = mfree(f->path);
+ if (clear && path_startswith(bind_mount_path(f), clear)) {
+ log_debug("%s is masked by %s.", bind_mount_path(f), clear);
+ f->path_malloc = mfree(f->path_malloc);
continue;
}
- clear = f->mode == INACCESSIBLE ? f->path : NULL;
+ clear = f->mode == INACCESSIBLE ? bind_mount_path(f) : NULL;
*t = *f;
t++;
@@ -387,7 +364,7 @@ static void drop_nop(BindMount *m, unsigned *n) {
/* Drops all entries which have an immediate parent that has the same type, as they are redundant. Assumes the
* list is ordered by prefixes. */
- for (f = m, t = m; f < m+*n; f++) {
+ for (f = m, t = m; f < m + *n; f++) {
/* Only suppress such subtrees for READONLY and READWRITE entries */
if (IN_SET(f->mode, READONLY, READWRITE)) {
@@ -396,7 +373,7 @@ static void drop_nop(BindMount *m, unsigned *n) {
/* Now let's find the first parent of the entry we are looking at. */
for (p = t-1; p >= m; p--) {
- if (path_startswith(f->path, p->path)) {
+ if (path_startswith(bind_mount_path(f), bind_mount_path(p))) {
found = true;
break;
}
@@ -404,8 +381,8 @@ static void drop_nop(BindMount *m, unsigned *n) {
/* We found it, let's see if it's the same mode, if so, we can drop this entry */
if (found && p->mode == f->mode) {
- log_debug("%s is redundant by %s", f->path, p->path);
- f->path = mfree(f->path);
+ log_debug("%s is redundant by %s", bind_mount_path(f), bind_mount_path(p));
+ f->path_malloc = mfree(f->path_malloc);
continue;
}
}
@@ -423,16 +400,17 @@ static void drop_outside_root(const char *root_directory, BindMount *m, unsigned
assert(m);
assert(n);
+ /* Nothing to do */
if (!root_directory)
return;
/* Drops all mounts that are outside of the root directory. */
- for (f = m, t = m; f < m+*n; f++) {
+ for (f = m, t = m; f < m + *n; f++) {
- if (!path_startswith(f->path, root_directory)) {
- log_debug("%s is outside of root directory.", f->path);
- f->path = mfree(f->path);
+ if (!path_startswith(bind_mount_path(f), root_directory)) {
+ log_debug("%s is outside of root directory.", bind_mount_path(f));
+ f->path_malloc = mfree(f->path_malloc);
continue;
}
@@ -548,11 +526,11 @@ static int mount_dev(BindMount *m) {
* missing when the service is started with RootDirectory. This is
* consistent with mount units creating the mount points when missing.
*/
- (void) mkdir_p_label(m->path, 0755);
+ (void) mkdir_p_label(bind_mount_path(m), 0755);
/* Unmount everything in old /dev */
- umount_recursive(m->path, 0);
- if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
+ umount_recursive(bind_mount_path(m), 0);
+ if (mount(dev, bind_mount_path(m), NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
}
@@ -592,7 +570,7 @@ static int apply_mount(
assert(m);
- log_debug("Applying namespace mount on %s", m->path);
+ log_debug("Applying namespace mount on %s", bind_mount_path(m));
switch (m->mode) {
@@ -602,10 +580,10 @@ static int apply_mount(
/* First, get rid of everything that is below if there
* is anything... Then, overmount it with an
* inaccessible path. */
- (void) umount_recursive(m->path, 0);
+ (void) umount_recursive(bind_mount_path(m), 0);
- if (lstat(m->path, &target) < 0)
- return log_debug_errno(errno, "Failed to lstat() %s to determine what to mount over it: %m", m->path);
+ if (lstat(bind_mount_path(m), &target) < 0)
+ return log_debug_errno(errno, "Failed to lstat() %s to determine what to mount over it: %m", bind_mount_path(m));
what = mode_to_inaccessible_node(target.st_mode);
if (!what) {
@@ -618,13 +596,13 @@ static int apply_mount(
case READONLY:
case READWRITE:
- r = path_is_mount_point(m->path, 0);
+ r = path_is_mount_point(bind_mount_path(m), 0);
if (r < 0)
- return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", m->path);
+ return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", bind_mount_path(m));
if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY bit for the mount point if needed. */
return 0;
/* This isn't a mount point yet, let's make it one. */
- what = m->path;
+ what = bind_mount_path(m);
break;
case PRIVATE_TMP:
@@ -644,10 +622,10 @@ static int apply_mount(
assert(what);
- if (mount(what, m->path, NULL, MS_BIND|MS_REC, NULL) < 0)
- return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, m->path);
+ if (mount(what, bind_mount_path(m), NULL, MS_BIND|MS_REC, NULL) < 0)
+ return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, bind_mount_path(m));
- log_debug("Successfully mounted %s to %s", what, m->path);
+ log_debug("Successfully mounted %s to %s", what, bind_mount_path(m));
return 0;
}
@@ -657,9 +635,9 @@ static int make_read_only(BindMount *m, char **blacklist) {
assert(m);
if (IN_SET(m->mode, INACCESSIBLE, READONLY))
- r = bind_remount_recursive(m->path, true, blacklist);
+ r = bind_remount_recursive(bind_mount_path(m), true, blacklist);
else if (m->mode == PRIVATE_DEV) { /* Can be readonly but the submounts can't*/
- if (mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
+ if (mount(NULL, bind_mount_path(m), NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
r = -errno;
} else
return 0;
@@ -671,9 +649,10 @@ static int make_read_only(BindMount *m, char **blacklist) {
return r;
}
+/* Chase symlinks and remove failed paths from mounts */
static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned *n) {
BindMount *f, *t;
- int r;
+ int r = 0;
assert(m);
assert(n);
@@ -684,21 +663,26 @@ static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned
for (f = m, t = m; f < m + *n; f++) {
_cleanup_free_ char *chased = NULL;
+ int k;
+
+ k = chase_symlinks(bind_mount_path(f), root_directory, &chased);
+ if (k < 0) {
+ /* Get only real errors */
+ if (r >= 0 && (k != -ENOENT || !f->ignore))
+ r = k;
- r = chase_symlinks(f->path, root_directory, &chased);
- if (r == -ENOENT && f->ignore) {
- /* Doesn't exist? Then remove it! */
- f->path = mfree(f->path);
+ /* Doesn't exist or failed? Then remove it and continue! */
+ log_debug_errno(k, "Failed to chase symlinks for %s: %m", bind_mount_path(f));
+ f->path_malloc = mfree(f->path_malloc);
continue;
}
- if (r < 0)
- return log_debug_errno(r, "Failed to chase symlinks for %s: %m", f->path);
- if (!path_equal(f->path, chased)) {
- log_debug("Chased %s → %s", f->path, chased);
- r = free_and_replace(f->path, chased);
- if (r < 0)
- return r;
+ if (!path_equal(bind_mount_path(f), chased)) {
+ log_debug("Chased %s → %s", bind_mount_path(f), chased);
+
+ free(f->path_malloc);
+ f->path_malloc = chased;
+ chased = NULL;
}
*t = *f;
@@ -706,7 +690,7 @@ static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned
}
*n = t - m;
- return 0;
+ return r;
}
static unsigned namespace_calculate_mounts(
@@ -778,67 +762,73 @@ int setup_namespace(
if (n_mounts > 0) {
m = mounts = (BindMount *) alloca0(n_mounts * sizeof(BindMount));
- r = append_mounts(&m, read_write_paths, READWRITE);
+ r = append_access_mounts(&m, read_write_paths, READWRITE);
if (r < 0)
goto finish;
- r = append_mounts(&m, read_only_paths, READONLY);
+ r = append_access_mounts(&m, read_only_paths, READONLY);
if (r < 0)
goto finish;
- r = append_mounts(&m, inaccessible_paths, INACCESSIBLE);
+ r = append_access_mounts(&m, inaccessible_paths, INACCESSIBLE);
if (r < 0)
goto finish;
if (tmp_dir) {
- r = append_one_mount(&m, root_directory, "/tmp", PRIVATE_TMP, false);
- if (r < 0)
- goto finish;
+ *(m++) = (BindMount) {
+ .path_const = "/tmp",
+ .mode = PRIVATE_TMP,
+ };
}
if (var_tmp_dir) {
- r = append_one_mount(&m, root_directory, "/var/tmp", PRIVATE_VAR_TMP, false);
- if (r < 0)
- goto finish;
+ *(m++) = (BindMount) {
+ .path_const = "/var/tmp",
+ .mode = PRIVATE_VAR_TMP,
+ };
}
if (ns_info->private_dev) {
- r = append_one_mount(&m, root_directory, "/dev", PRIVATE_DEV, false);
- if (r < 0)
- goto finish;
+ *(m++) = (BindMount) {
+ .path_const = "/dev",
+ .mode = PRIVATE_DEV,
+ };
}
if (ns_info->protect_kernel_tunables) {
- r = append_protect_kernel_tunables(&m, root_directory,
- ns_info->ignore_protect_paths);
+ r = append_static_mounts(&m, protect_kernel_tunables_table, ELEMENTSOF(protect_kernel_tunables_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
}
if (ns_info->protect_kernel_modules) {
- r = append_protect_kernel_modules(&m, root_directory,
- ns_info->ignore_protect_paths);
+ r = append_static_mounts(&m, protect_kernel_modules_table, ELEMENTSOF(protect_kernel_modules_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
}
if (ns_info->protect_control_groups) {
- r = append_one_mount(&m, root_directory, "/sys/fs/cgroup", READONLY, false);
- if (r < 0)
- goto finish;
+ *(m++) = (BindMount) {
+ .path_const = "/sys/fs/cgroup",
+ .mode = READONLY,
+ };
}
- r = append_protect_home(&m, root_directory, protect_home,
- ns_info->ignore_protect_paths);
+ r = append_protect_home(&m, protect_home, ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
- r = append_protect_system(&m, root_directory, protect_system, false);
+ r = append_protect_system(&m, protect_system, false);
if (r < 0)
goto finish;
assert(mounts + n_mounts == m);
+ /* Prepend the root directory where that's necessary */
+ r = prefix_where_needed(mounts, n_mounts, root_directory);
+ if (r < 0)
+ goto finish;
+
/* Resolve symlinks manually first, as mount() will always follow them relative to the host's
* root. Moreover we want to suppress duplicates based on the resolved paths. This of course is a bit
* racy. */
@@ -895,7 +885,7 @@ int setup_namespace(
/* Create a blacklist we can pass to bind_mount_recursive() */
blacklist = newa(char*, n_mounts+1);
for (j = 0; j < n_mounts; j++)
- blacklist[j] = (char*) mounts[j].path;
+ blacklist[j] = (char*) bind_mount_path(mounts+j);
blacklist[j] = NULL;
/* Second round, flip the ro bits if necessary. */
@@ -925,7 +915,7 @@ int setup_namespace(
finish:
for (m = mounts; m < mounts + n_mounts; m++)
- free(m->path);
+ free(m->path_malloc);
return r;
}
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index a61677e645..e824a2233c 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -66,6 +66,14 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="GetJobAfter"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
+ send_member="GetJobBefore"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="ListUnits"/>
<allow send_destination="org.freedesktop.systemd1"
@@ -250,6 +258,14 @@
send_interface="org.freedesktop.systemd1.Job"
send_member="Cancel"/>
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Job"
+ send_member="GetAfter"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Job"
+ send_member="GetBefore"/>
+
<allow receive_sender="org.freedesktop.systemd1"/>
</policy>
diff --git a/src/core/unit.c b/src/core/unit.c
index 7b78ba9a9e..cba6342eca 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -389,10 +389,8 @@ void unit_add_to_gc_queue(Unit *u) {
if (unit_check_gc(u))
return;
- LIST_PREPEND(gc_queue, u->manager->gc_queue, u);
+ LIST_PREPEND(gc_queue, u->manager->gc_unit_queue, u);
u->in_gc_queue = true;
-
- u->manager->n_in_gc_queue++;
}
void unit_add_to_dbus_queue(Unit *u) {
@@ -570,10 +568,8 @@ void unit_free(Unit *u) {
if (u->in_cleanup_queue)
LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
- if (u->in_gc_queue) {
- LIST_REMOVE(gc_queue, u->manager->gc_queue, u);
- u->manager->n_in_gc_queue--;
- }
+ if (u->in_gc_queue)
+ LIST_REMOVE(gc_queue, u->manager->gc_unit_queue, u);
if (u->in_cgroup_queue)
LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
@@ -3440,14 +3436,6 @@ int unit_patch_contexts(Unit *u) {
ec->working_directory_missing_ok = true;
}
- if (MANAGER_IS_USER(u->manager) &&
- (ec->syscall_whitelist ||
- !set_isempty(ec->syscall_filter) ||
- !set_isempty(ec->syscall_archs) ||
- ec->address_families_whitelist ||
- !set_isempty(ec->address_families)))
- ec->no_new_privileges = true;
-
if (ec->private_devices)
ec->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) | (UINT64_C(1) << CAP_SYS_RAWIO));
diff --git a/src/core/unit.h b/src/core/unit.h
index 1ef92f3263..8052c234fd 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -441,6 +441,9 @@ struct UnitVTable {
/* True if transient units of this type are OK */
bool can_transient:1;
+
+ /* True if queued jobs of this type should be GC'ed if no other job needs them anymore */
+ bool gc_jobs:1;
};
extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 46507de937..f6a912ae06 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -141,13 +141,14 @@ static bool mount_in_initrd(struct mntent *me) {
streq(me->mnt_dir, "/usr");
}
-static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
+static int write_timeout(FILE *f, const char *where, const char *opts,
+ const char *filter, const char *variable) {
_cleanup_free_ char *timeout = NULL;
char timespan[FORMAT_TIMESPAN_MAX];
usec_t u;
int r;
- r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, NULL);
+ r = fstab_filter_options(opts, filter, NULL, &timeout, NULL);
if (r < 0)
return log_warning_errno(r, "Failed to parse options: %m");
if (r == 0)
@@ -159,11 +160,21 @@ static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
return 0;
}
- fprintf(f, "TimeoutIdleSec=%s\n", format_timespan(timespan, sizeof(timespan), u, 0));
+ fprintf(f, "%s=%s\n", variable, format_timespan(timespan, sizeof(timespan), u, 0));
return 0;
}
+static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
+ return write_timeout(f, where, opts,
+ "x-systemd.idle-timeout\0", "TimeoutIdleSec");
+}
+
+static int write_mount_timeout(FILE *f, const char *where, const char *opts) {
+ return write_timeout(f, where, opts,
+ "x-systemd.mount-timeout\0", "TimeoutSec");
+}
+
static int write_requires_after(FILE *f, const char *opts) {
_cleanup_strv_free_ char **names = NULL, **units = NULL;
_cleanup_free_ char *res = NULL;
@@ -327,6 +338,10 @@ static int add_mount(
if (r < 0)
return r;
+ r = write_mount_timeout(f, where, opts);
+ if (r < 0)
+ return r;
+
if (!isempty(filtered) && !streq(filtered, "defaults"))
fprintf(f, "Options=%s\n", filtered);
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index 99f690897d..5aa8aca426 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -32,7 +32,8 @@
int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr,
- size_t mac_addr_len, uint16_t arp_type);
+ size_t mac_addr_len, uint16_t arp_type,
+ uint16_t port);
int dhcp_network_bind_udp_socket(be32_t address, uint16_t port);
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
const void *packet, size_t len);
@@ -57,7 +58,7 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
uint16_t source, be32_t destination_addr,
uint16_t destination, uint16_t len);
-int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum);
+int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
/* If we are invoking callbacks of a dhcp-client, ensure unreffing the
* client from the callback doesn't destroy the object we are working
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
index a9f5a0a5de..3c85bb0b54 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -36,7 +36,8 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
size_t mac_addr_len,
const uint8_t *bcast_addr,
const struct ether_addr *eth_mac,
- uint16_t arp_type, uint8_t dhcp_hlen) {
+ uint16_t arp_type, uint8_t dhcp_hlen,
+ uint16_t port) {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */
@@ -53,7 +54,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0), /* UDP destination port == DHCP client port ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0), /* UDP destination port == DHCP client port ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */
@@ -125,7 +126,8 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr,
- size_t mac_addr_len, uint16_t arp_type) {
+ size_t mac_addr_len, uint16_t arp_type,
+ uint16_t port) {
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* Default broadcast address for IPoIB */
static const uint8_t ib_bcast[] = {
@@ -151,7 +153,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
return -EINVAL;
return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
- bcast_addr, &eth_mac, arp_type, dhcp_hlen);
+ bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
}
int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) {
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index 8be774061d..40442b3636 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -114,7 +114,7 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
}
-int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) {
+int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) {
size_t hdrlen;
assert(packet);
@@ -160,10 +160,10 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) {
return -EINVAL;
}
- if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) {
+ if (be16toh(packet->udp.dest) != port) {
log_debug("ignoring packet: to port %u, which "
"is not the DHCP client port (%u)",
- be16toh(packet->udp.dest), DHCP_PORT_CLIENT);
+ be16toh(packet->udp.dest), port);
return -EINVAL;
}
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 5ccb23922c..6475da2c2a 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -55,6 +55,7 @@ struct sd_dhcp_client {
sd_event_source *timeout_resend;
int ifindex;
int fd;
+ uint16_t port;
union sockaddr_union link;
sd_event_source *receive_message;
bool request_broadcast;
@@ -426,6 +427,17 @@ int sd_dhcp_client_set_vendor_class_identifier(
return 0;
}
+int sd_dhcp_client_set_client_port(
+ sd_dhcp_client *client,
+ uint16_t port) {
+
+ assert_return(client, -EINVAL);
+
+ client->port = port;
+
+ return 0;
+}
+
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
assert_return(client, -EINVAL);
assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
@@ -668,7 +680,7 @@ static int dhcp_client_send_raw(
DHCPPacket *packet,
size_t len) {
- dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
+ dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
INADDR_BROADCAST, DHCP_PORT_SERVER, len);
return dhcp_network_send_raw_socket(client->fd, &client->link,
@@ -1120,7 +1132,7 @@ static int client_start_delayed(sd_dhcp_client *client) {
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
client->xid, client->mac_addr,
- client->mac_addr_len, client->arp_type);
+ client->mac_addr_len, client->arp_type, client->port);
if (r < 0) {
client_stop(client, r);
return r;
@@ -1170,7 +1182,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
client->xid, client->mac_addr,
- client->mac_addr_len, client->arp_type);
+ client->mac_addr_len, client->arp_type,
+ client->port);
if (r < 0) {
client_stop(client, r);
return 0;
@@ -1555,8 +1568,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
goto error;
}
- r = dhcp_network_bind_udp_socket(client->lease->address,
- DHCP_PORT_CLIENT);
+ r = dhcp_network_bind_udp_socket(client->lease->address, client->port);
if (r < 0) {
log_dhcp_client(client, "could not bind UDP socket");
goto error;
@@ -1766,7 +1778,7 @@ static int client_receive_message_raw(
}
}
- r = dhcp_packet_verify_headers(packet, len, checksum);
+ r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
if (r < 0)
return 0;
@@ -1891,6 +1903,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) {
client->fd = -1;
client->attempt = 1;
client->mtu = DHCP_DEFAULT_MIN_SIZE;
+ client->port = DHCP_PORT_CLIENT;
client->req_opts_size = ELEMENTSOF(default_req_opts);
client->req_opts = memdup(default_req_opts, client->req_opts_size);
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index 2a101cb1fe..c10ca74b86 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -195,7 +195,7 @@ int dhcp_network_bind_raw_socket(
union sockaddr_union *link,
uint32_t id,
const uint8_t *addr, size_t addr_len,
- uint16_t arp_type) {
+ uint16_t arp_type, uint16_t port) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
return -errno;
diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c
index 09cbd9ab44..a05794941f 100644
--- a/src/libsystemd/sd-bus/busctl-introspect.c
+++ b/src/libsystemd/sd-bus/busctl-introspect.c
@@ -143,9 +143,7 @@ static int parse_xml_annotation(Context *context, uint64_t *flags) {
case STATE_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
- free(field);
- field = name;
- name = NULL;
+ free_and_replace(field, name);
state = STATE_ANNOTATION;
} else {
@@ -158,9 +156,7 @@ static int parse_xml_annotation(Context *context, uint64_t *flags) {
case STATE_VALUE:
if (t == XML_ATTRIBUTE_VALUE) {
- free(value);
- value = name;
- name = NULL;
+ free_and_replace(value, name);
state = STATE_ANNOTATION;
} else {
@@ -194,6 +190,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
STATE_SIGNAL_ARG,
STATE_SIGNAL_ARG_NAME,
STATE_SIGNAL_ARG_TYPE,
+ STATE_SIGNAL_ARG_DIRECTION,
STATE_PROPERTY,
STATE_PROPERTY_NAME,
STATE_PROPERTY_TYPE,
@@ -350,11 +347,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_INTERFACE_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
- if (n_depth == 0) {
- free(context->interface_name);
- context->interface_name = name;
- name = NULL;
- }
+ if (n_depth == 0)
+ free_and_replace(context->interface_name, name);
state = STATE_INTERFACE;
} else {
@@ -409,12 +403,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_METHOD_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
-
- if (n_depth == 0) {
- free(context->member_name);
- context->member_name = name;
- name = NULL;
- }
+ if (n_depth == 0)
+ free_and_replace(context->member_name, name);
state = STATE_METHOD;
} else {
@@ -432,7 +422,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
else if (streq_ptr(name, "type"))
state = STATE_METHOD_ARG_TYPE;
else if (streq_ptr(name, "direction"))
- state = STATE_METHOD_ARG_DIRECTION;
+ state = STATE_METHOD_ARG_DIRECTION;
else {
log_error("Unexpected method <arg> attribute %s.", name);
return -EBADMSG;
@@ -458,7 +448,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
} else if (streq(argument_direction, "out")) {
if (!strextend(&context->member_result, argument_type, NULL))
return log_oom();
- }
+ } else
+ log_error("Unexpected method <arg> direction value '%s'.", argument_direction);
}
argument_type = mfree(argument_type);
@@ -487,9 +478,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_METHOD_ARG_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
- free(argument_type);
- argument_type = name;
- name = NULL;
+ free_and_replace(argument_type, name);
state = STATE_METHOD_ARG;
} else {
@@ -502,9 +491,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_METHOD_ARG_DIRECTION:
if (t == XML_ATTRIBUTE_VALUE) {
- free(argument_direction);
- argument_direction = name;
- name = NULL;
+ free_and_replace(argument_direction, name);
state = STATE_METHOD_ARG;
} else {
@@ -559,12 +546,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_SIGNAL_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
-
- if (n_depth == 0) {
- free(context->member_name);
- context->member_name = name;
- name = NULL;
- }
+ if (n_depth == 0)
+ free_and_replace(context->member_name, name);
state = STATE_SIGNAL;
} else {
@@ -582,6 +565,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
state = STATE_SIGNAL_ARG_NAME;
else if (streq_ptr(name, "type"))
state = STATE_SIGNAL_ARG_TYPE;
+ else if (streq_ptr(name, "direction"))
+ state = STATE_SIGNAL_ARG_DIRECTION;
else {
log_error("Unexpected signal <arg> attribute %s.", name);
return -EBADMSG;
@@ -599,8 +584,11 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
(t == XML_TAG_CLOSE && streq_ptr(name, "arg"))) {
if (argument_type) {
- if (!strextend(&context->member_signature, argument_type, NULL))
- return log_oom();
+ if (!argument_direction || streq(argument_direction, "out")) {
+ if (!strextend(&context->member_signature, argument_type, NULL))
+ return log_oom();
+ } else
+ log_error("Unexpected signal <arg> direction value '%s'.", argument_direction);
argument_type = mfree(argument_type);
}
@@ -627,9 +615,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_SIGNAL_ARG_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
- free(argument_type);
- argument_type = name;
- name = NULL;
+ free_and_replace(argument_type, name);
state = STATE_SIGNAL_ARG;
} else {
@@ -639,6 +625,19 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
break;
+ case STATE_SIGNAL_ARG_DIRECTION:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ free_and_replace(argument_direction, name);
+
+ state = STATE_SIGNAL_ARG;
+ } else {
+ log_error("Unexpected token in signal <arg>. (4)");
+ return -EINVAL;
+ }
+
+ break;
+
case STATE_PROPERTY:
if (t == XML_ATTRIBUTE_NAME) {
@@ -688,12 +687,9 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_PROPERTY_NAME:
if (t == XML_ATTRIBUTE_VALUE) {
+ if (n_depth == 0)
+ free_and_replace(context->member_name, name);
- if (n_depth == 0) {
- free(context->member_name);
- context->member_name = name;
- name = NULL;
- }
state = STATE_PROPERTY;
} else {
log_error("Unexpected token in <property>. (2)");
@@ -705,12 +701,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth
case STATE_PROPERTY_TYPE:
if (t == XML_ATTRIBUTE_VALUE) {
-
- if (n_depth == 0) {
- free(context->member_signature);
- context->member_signature = name;
- name = NULL;
- }
+ if (n_depth == 0)
+ free_and_replace(context->member_signature, name);
state = STATE_PROPERTY;
} else {
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index f8e18f23fd..0d8d99c56d 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -224,13 +224,8 @@ static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
return -ENODATA;
if (r < 0)
return r;
- if (isempty(s)) {
- *ret = NULL;
- return 0;
- }
- x = s;
- for (;;) {
+ for (x = s;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&x, &word, NULL, 0);
@@ -243,15 +238,14 @@ static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
if (r < 0)
return r;
- if (!GREEDY_REALLOC(ifis, allocated, c + 1))
+ if (!GREEDY_REALLOC(ifis, allocated, c + 2))
return -ENOMEM;
ifis[c++] = ifindex;
}
- if (!GREEDY_REALLOC(ifis, allocated, c + 1))
- return -ENOMEM;
- ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/
+ if (ifis)
+ ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/
*ret = ifis;
ifis = NULL;
diff --git a/src/network/.gitignore b/src/network/.gitignore
index aca55206b7..230671763d 100644
--- a/src/network/.gitignore
+++ b/src/network/.gitignore
@@ -1,3 +1,2 @@
/networkd-network-gperf.c
-/networkd-netdev-gperf.c
/networkd-gperf.c
diff --git a/src/network/netdev/.gitignore b/src/network/netdev/.gitignore
new file mode 100644
index 0000000000..0f1a65d2e6
--- /dev/null
+++ b/src/network/netdev/.gitignore
@@ -0,0 +1 @@
+/netdev-gperf.c
diff --git a/src/network/networkd-netdev-bond.c b/src/network/netdev/bond.c
index 46d1669337..19b0e8da40 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/netdev/bond.c
@@ -27,7 +27,7 @@
#include "conf-parser.h"
#include "extract-word.h"
#include "missing.h"
-#include "networkd-netdev-bond.h"
+#include "netdev/bond.h"
#include "string-table.h"
#include "string-util.h"
diff --git a/src/network/networkd-netdev-bond.h b/src/network/netdev/bond.h
index b941edb344..fb88b538ed 100644
--- a/src/network/networkd-netdev-bond.h
+++ b/src/network/netdev/bond.h
@@ -22,7 +22,7 @@
#include "in-addr-util.h"
#include "list.h"
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
/*
* Maximum number of targets supported by the kernel for a single
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/netdev/bridge.c
index 002ad94210..08e31b974f 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/netdev/bridge.c
@@ -22,8 +22,8 @@
#include "missing.h"
#include "netlink-util.h"
-#include "networkd.h"
-#include "networkd-netdev-bridge.h"
+#include "netdev/bridge.h"
+#include "networkd-manager.h"
/* callback for brige netdev's parameter set */
static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/netdev/bridge.h
index 53f72f1ea5..093c60d5b5 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/netdev/bridge.h
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
typedef struct Bridge {
NetDev meta;
diff --git a/src/network/networkd-netdev-dummy.c b/src/network/netdev/dummy.c
index 6617a86c20..5e6e162931 100644
--- a/src/network/networkd-netdev-dummy.c
+++ b/src/network/netdev/dummy.c
@@ -19,7 +19,7 @@
***/
-#include "networkd-netdev-dummy.h"
+#include "netdev/dummy.h"
const NetDevVTable dummy_vtable = {
.object_size = sizeof(Dummy),
diff --git a/src/network/networkd-netdev-dummy.h b/src/network/netdev/dummy.h
index efe302267e..a908400459 100644
--- a/src/network/networkd-netdev-dummy.h
+++ b/src/network/netdev/dummy.h
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
typedef struct Dummy {
NetDev meta;
diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/netdev/ipvlan.c
index af4177e43a..3b5c30fed8 100644
--- a/src/network/networkd-netdev-ipvlan.c
+++ b/src/network/netdev/ipvlan.c
@@ -20,7 +20,7 @@
#include <net/if.h>
#include "conf-parser.h"
-#include "networkd-netdev-ipvlan.h"
+#include "netdev/ipvlan.h"
#include "string-table.h"
static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/netdev/ipvlan.h
index 10d4079844..7d7d0184f1 100644
--- a/src/network/networkd-netdev-ipvlan.h
+++ b/src/network/netdev/ipvlan.h
@@ -20,7 +20,7 @@
***/
#include "missing.h"
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
typedef enum IPVlanMode {
NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/netdev/macvlan.c
index 48e98aa51b..93f650def5 100644
--- a/src/network/networkd-netdev-macvlan.c
+++ b/src/network/netdev/macvlan.c
@@ -20,7 +20,7 @@
#include <net/if.h>
#include "conf-parser.h"
-#include "networkd-netdev-macvlan.h"
+#include "netdev/macvlan.h"
#include "string-table.h"
static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/netdev/macvlan.h
index 3663f4f051..118d55658c 100644
--- a/src/network/networkd-netdev-macvlan.h
+++ b/src/network/netdev/macvlan.h
@@ -21,7 +21,7 @@
typedef struct MacVlan MacVlan;
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
typedef enum MacVlanMode {
NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index 323eaa8032..b3461e39a9 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -2,17 +2,17 @@
#include <stddef.h>
#include "conf-parser.h"
#include "network-internal.h"
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-bridge.h"
-#include "networkd-netdev-ipvlan.h"
-#include "networkd-netdev-macvlan.h"
-#include "networkd-netdev-tunnel.h"
-#include "networkd-netdev-tuntap.h"
-#include "networkd-netdev-veth.h"
-#include "networkd-netdev-vlan.h"
-#include "networkd-netdev-vxlan.h"
-#include "networkd-netdev-vrf.h"
-#include "networkd-netdev.h"
+#include "netdev/bond.h"
+#include "netdev/bridge.h"
+#include "netdev/ipvlan.h"
+#include "netdev/macvlan.h"
+#include "netdev/tunnel.h"
+#include "netdev/tuntap.h"
+#include "netdev/veth.h"
+#include "netdev/vlan.h"
+#include "netdev/vxlan.h"
+#include "netdev/vrf.h"
+#include "netdev/netdev.h"
#include "vlan-util.h"
%}
struct ConfigPerfItem;
diff --git a/src/network/networkd-netdev.c b/src/network/netdev/netdev.c
index a210ba1242..9b9e83d9db 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/netdev/netdev.c
@@ -26,13 +26,26 @@
#include "list.h"
#include "netlink-util.h"
#include "network-internal.h"
-#include "networkd-netdev.h"
-#include "networkd.h"
+#include "netdev/netdev.h"
+#include "networkd-manager.h"
#include "siphash24.h"
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "netdev/bridge.h"
+#include "netdev/bond.h"
+#include "netdev/vlan.h"
+#include "netdev/macvlan.h"
+#include "netdev/ipvlan.h"
+#include "netdev/vxlan.h"
+#include "netdev/tunnel.h"
+#include "netdev/tuntap.h"
+#include "netdev/veth.h"
+#include "netdev/dummy.h"
+#include "netdev/vrf.h"
+#include "netdev/vcan.h"
+
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_BRIDGE] = &bridge_vtable,
[NETDEV_KIND_BOND] = &bond_vtable,
diff --git a/src/network/networkd-netdev.h b/src/network/netdev/netdev.h
index 70ff947b99..70ff947b99 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/netdev/netdev.h
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/netdev/tunnel.c
index 9138ee4511..b03e770061 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/netdev/tunnel.c
@@ -28,7 +28,7 @@
#include "conf-parser.h"
#include "missing.h"
#include "networkd-link.h"
-#include "networkd-netdev-tunnel.h"
+#include "netdev/tunnel.h"
#include "parse-util.h"
#include "string-table.h"
#include "string-util.h"
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/netdev/tunnel.h
index 32a46bd82f..d78c6135ee 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/netdev/tunnel.h
@@ -21,7 +21,7 @@
#include "in-addr-util.h"
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
typedef enum Ip6TnlMode {
NETDEV_IP6_TNL_MODE_IP6IP6,
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/netdev/tuntap.c
index 088a4d8d32..3d62808842 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/netdev/tuntap.c
@@ -27,7 +27,7 @@
#include "alloc-util.h"
#include "fd-util.h"
-#include "networkd-netdev-tuntap.h"
+#include "netdev/tuntap.h"
#include "user-util.h"
#define TUN_DEV "/dev/net/tun"
diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/netdev/tuntap.h
index 120f00a353..95d3fcf1e9 100644
--- a/src/network/networkd-netdev-tuntap.h
+++ b/src/network/netdev/tuntap.h
@@ -21,7 +21,7 @@
typedef struct TunTap TunTap;
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
struct TunTap {
NetDev meta;
diff --git a/src/network/networkd-netdev-vcan.c b/src/network/netdev/vcan.c
index bfce6e1962..7f56702938 100644
--- a/src/network/networkd-netdev-vcan.c
+++ b/src/network/netdev/vcan.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "networkd-netdev-vcan.h"
+#include "netdev/vcan.h"
const NetDevVTable vcan_vtable = {
.object_size = sizeof(VCan),
diff --git a/src/network/networkd-netdev-vcan.h b/src/network/netdev/vcan.h
index 6ba47fd70e..00838b7675 100644
--- a/src/network/networkd-netdev-vcan.h
+++ b/src/network/netdev/vcan.h
@@ -23,7 +23,7 @@ typedef struct VCan VCan;
#include <linux/can/netlink.h>
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
struct VCan {
NetDev meta;
diff --git a/src/network/networkd-netdev-veth.c b/src/network/netdev/veth.c
index b122a06c25..350b59bf03 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/netdev/veth.c
@@ -22,7 +22,7 @@
#include "sd-netlink.h"
-#include "networkd-netdev-veth.h"
+#include "netdev/veth.h"
static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
Veth *v;
diff --git a/src/network/networkd-netdev-veth.h b/src/network/netdev/veth.h
index e69bfbc8f0..b00ce476e8 100644
--- a/src/network/networkd-netdev-veth.h
+++ b/src/network/netdev/veth.h
@@ -21,7 +21,7 @@
typedef struct Veth Veth;
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
struct Veth {
NetDev meta;
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/netdev/vlan.c
index 3cc072388f..28c061fa4f 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/netdev/vlan.c
@@ -19,7 +19,7 @@
#include <net/if.h>
-#include "networkd-netdev-vlan.h"
+#include "netdev/vlan.h"
#include "vlan-util.h"
static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
diff --git a/src/network/networkd-netdev-vlan.h b/src/network/netdev/vlan.h
index 2dfe314b6e..fade899997 100644
--- a/src/network/networkd-netdev-vlan.h
+++ b/src/network/netdev/vlan.h
@@ -21,7 +21,7 @@
typedef struct VLan VLan;
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
struct VLan {
NetDev meta;
diff --git a/src/network/networkd-netdev-vrf.c b/src/network/netdev/vrf.c
index 89bd142e8c..f48b413102 100644
--- a/src/network/networkd-netdev-vrf.c
+++ b/src/network/netdev/vrf.c
@@ -21,7 +21,7 @@
#include "sd-netlink.h"
#include "missing.h"
-#include "networkd-netdev-vrf.h"
+#include "netdev/vrf.h"
static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
Vrf *v;
diff --git a/src/network/networkd-netdev-vrf.h b/src/network/netdev/vrf.h
index 3d92a26a4d..00f54ed96d 100644
--- a/src/network/networkd-netdev-vrf.h
+++ b/src/network/netdev/vrf.h
@@ -21,7 +21,7 @@
typedef struct Vrf Vrf;
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
struct Vrf {
NetDev meta;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/netdev/vxlan.c
index 706e52b698..10c892b044 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/netdev/vxlan.c
@@ -28,7 +28,7 @@
#include "missing.h"
#include "networkd-link.h"
-#include "networkd-netdev-vxlan.h"
+#include "netdev/vxlan.h"
static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
VxLan *v;
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/netdev/vxlan.h
index 3906820afb..6c3081d5fc 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/netdev/vxlan.h
@@ -22,7 +22,7 @@
typedef struct VxLan VxLan;
#include "in-addr-util.h"
-#include "networkd-netdev.h"
+#include "netdev/netdev.h"
#define VXLAN_VID_MAX (1u << 24) - 1
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index ebc6c9eb9e..a63b925a4a 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -19,7 +19,7 @@
#include "alloc-util.h"
#include "networkd-address-pool.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "set.h"
#include "string-util.h"
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index ed52d5e42d..2b698d9531 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -24,7 +24,7 @@
#include "firewall-util.h"
#include "netlink-util.h"
#include "networkd-address.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "parse-util.h"
#include "set.h"
#include "socket-util.h"
diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c
index 18ecd86858..fa5d3ee7fa 100644
--- a/src/network/networkd-brvlan.c
+++ b/src/network/networkd-brvlan.c
@@ -25,7 +25,9 @@
#include "conf-parser.h"
#include "netlink-util.h"
#include "networkd-brvlan.h"
-#include "networkd.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "networkd-network.h"
#include "parse-util.h"
#include "vlan-util.h"
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
index 49bb8c18f6..aaa27f311d 100644
--- a/src/network/networkd-conf.c
+++ b/src/network/networkd-conf.c
@@ -22,8 +22,10 @@
#include "conf-parser.h"
#include "def.h"
#include "dhcp-identifier.h"
+#include "extract-word.h"
#include "hexdecoct.h"
#include "networkd-conf.h"
+#include "networkd-network.h"
#include "string-table.h"
int manager_parse_config_file(Manager *m) {
diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h
index c7bfb42a72..93819626ba 100644
--- a/src/network/networkd-conf.h
+++ b/src/network/networkd-conf.h
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "networkd.h"
+typedef struct Manager Manager;
int manager_parse_config_file(Manager *m);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 76d3d132ea..614bceefab 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -24,7 +24,9 @@
#include "dhcp-lease-internal.h"
#include "hostname-util.h"
#include "network-internal.h"
-#include "networkd.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "networkd-network.h"
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
@@ -630,6 +632,12 @@ int dhcp4_configure(Link *link) {
return r;
}
+ if (link->network->dhcp_client_port) {
+ r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
+ if (r < 0)
+ return r;
+ }
+
switch (link->network->dhcp_client_identifier) {
case DHCP_CLIENT_ID_DUID: {
/* If configured, apply user specified DUID and/or IAID */
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 15acf56a5f..6ba2d170e7 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -23,7 +23,8 @@
#include "sd-dhcp6-client.h"
#include "network-internal.h"
-#include "networkd.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
@@ -125,7 +126,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
assert(link);
assert(link->network);
- assert(link->manager);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index ed5a47589e..3d7f4d2b2d 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -22,9 +22,10 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "netdev/bridge.h"
#include "netlink-util.h"
#include "networkd-fdb.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "util.h"
#include "vlan-util.h"
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
index 3fdfe74955..eca436d9fd 100644
--- a/src/network/networkd-gperf.gperf
+++ b/src/network/networkd-gperf.gperf
@@ -2,6 +2,7 @@
#include <stddef.h>
#include "conf-parser.h"
#include "networkd-conf.h"
+#include "networkd-manager.h"
%}
struct ConfigPerfItem;
%null_strings
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 2d81311e81..7ba05dbec3 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -21,7 +21,9 @@
#include <linux/if.h>
#include "network-internal.h"
-#include "networkd.h"
+#include "networkd-address.h"
+#include "networkd-manager.h"
+#include "networkd-link.h"
static int ipv4ll_address_lost(Link *link) {
_cleanup_address_free_ Address *address = NULL;
@@ -171,7 +173,6 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
assert(link);
assert(link->network);
- assert(link->manager);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index 532557ed6c..c39c648334 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -20,7 +20,7 @@
#include "alloc-util.h"
#include "bus-util.h"
#include "networkd-link.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "parse-util.h"
#include "strv.h"
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index aefe7335b9..0b634572a9 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -29,8 +29,8 @@
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-lldp-tx.h"
+#include "networkd-manager.h"
#include "networkd-ndisc.h"
-#include "networkd.h"
#include "set.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -2632,7 +2632,7 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
log_link_debug(link, "Ignoring DHCP server for loopback link");
}
- r = network_apply(link->manager, network, link);
+ r = network_apply(network, link);
if (r < 0)
return r;
}
@@ -2728,7 +2728,7 @@ static int link_load(Link *link) {
goto network_file_fail;
}
- r = network_apply(link->manager, network, link);
+ r = network_apply(network, link);
if (r < 0)
return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
}
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
index 3aa768388b..2de63ce746 100644
--- a/src/network/networkd-lldp-tx.c
+++ b/src/network/networkd-lldp-tx.c
@@ -26,7 +26,7 @@
#include "fileio.h"
#include "hostname-util.h"
#include "networkd-lldp-tx.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "parse-util.h"
#include "random-util.h"
#include "socket-util.h"
diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
index 0c429b9471..cbb1b93031 100644
--- a/src/network/networkd-manager-bus.c
+++ b/src/network/networkd-manager-bus.c
@@ -19,7 +19,7 @@
#include "alloc-util.h"
#include "bus-util.h"
-#include "networkd.h"
+#include "networkd-manager.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 9174dcc7f4..a1252c9b51 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -33,7 +33,7 @@
#include "libudev-private.h"
#include "local-addresses.h"
#include "netlink-util.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "ordered-set.h"
#include "path-util.h"
#include "set.h"
diff --git a/src/network/networkd.h b/src/network/networkd-manager.h
index cb1b73145e..a90d9a933f 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd-manager.h
@@ -32,20 +32,7 @@
#include "networkd-address-pool.h"
#include "networkd-link.h"
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-bridge.h"
-#include "networkd-netdev-dummy.h"
-#include "networkd-netdev-ipvlan.h"
-#include "networkd-netdev-macvlan.h"
-#include "networkd-netdev-tunnel.h"
-#include "networkd-netdev-tuntap.h"
-#include "networkd-netdev-veth.h"
-#include "networkd-netdev-vlan.h"
-#include "networkd-netdev-vrf.h"
-#include "networkd-netdev-vxlan.h"
-#include "networkd-netdev-vcan.h"
#include "networkd-network.h"
-#include "networkd-util.h"
extern const char* const network_dirs[];
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 4853791aa5..70283e5347 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -18,11 +18,12 @@
***/
#include <netinet/icmp6.h>
+#include <arpa/inet.h>
#include "sd-ndisc.h"
-#include "networkd.h"
#include "networkd-ndisc.h"
+#include "networkd-route.h"
#define NDISC_DNSSL_MAX 64U
#define NDISC_RDNSS_MAX 64U
diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c
index 6e21676d23..3b835b52f9 100644
--- a/src/network/networkd-network-bus.c
+++ b/src/network/networkd-network-bus.c
@@ -18,7 +18,7 @@
***/
#include "alloc-util.h"
-#include "networkd.h"
+#include "networkd-manager.h"
#include "string-util.h"
#include "strv.h"
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index bcf8186c33..efd3176ac3 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -1,8 +1,8 @@
%{
#include <stddef.h>
#include "conf-parser.h"
-#include "networkd.h"
#include "networkd-conf.h"
+#include "networkd-network.h"
#include "network-internal.h"
#include "vlan-util.h"
%}
@@ -100,6 +100,7 @@ DHCP.RouteMetric, config_parse_unsigned,
DHCP.RouteTable, config_parse_dhcp_route_table, 0, offsetof(Network, dhcp_route_table)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
+DHCP.ListenPort, config_parse_uint32, 0, offsetof(Network, dhcp_client_port)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.RouteTable, config_parse_dhcp_route_table, 0, offsetof(Network, ipv6_accept_ra_route_table)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 0dc00e874d..31e899eecd 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -27,8 +27,8 @@
#include "fd-util.h"
#include "hostname-util.h"
#include "network-internal.h"
+#include "networkd-manager.h"
#include "networkd-network.h"
-#include "networkd.h"
#include "parse-util.h"
#include "set.h"
#include "stat-util.h"
@@ -368,10 +368,9 @@ int network_get(Manager *manager, struct udev_device *device,
return -ENOENT;
}
-int network_apply(Manager *manager, Network *network, Link *link) {
+int network_apply(Network *network, Link *link) {
int r;
- assert(manager);
assert(network);
assert(link);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 42fc82d392..e956a59fe3 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -31,9 +31,9 @@
#include "networkd-brvlan.h"
#include "networkd-fdb.h"
#include "networkd-lldp-tx.h"
-#include "networkd-netdev.h"
#include "networkd-route.h"
#include "networkd-util.h"
+#include "netdev/netdev.h"
#define DHCP_ROUTE_METRIC 1024
#define IPV4LL_ROUTE_METRIC 2048
@@ -124,6 +124,7 @@ struct Network {
bool dhcp_use_timezone;
unsigned dhcp_route_metric;
uint32_t dhcp_route_table;
+ uint32_t dhcp_client_port;
/* DHCP Server Support */
bool dhcp_server;
@@ -212,7 +213,7 @@ int network_load(Manager *manager);
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);
+int network_apply(Network *network, Link *link);
bool network_has_static_ipv6_addresses(Network *network);
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 6f60ee5e31..f78e106991 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -21,8 +21,8 @@
#include "conf-parser.h"
#include "in-addr-util.h"
#include "netlink-util.h"
+#include "networkd-manager.h"
#include "networkd-route.h"
-#include "networkd.h"
#include "parse-util.h"
#include "set.h"
#include "string-util.h"
diff --git a/src/network/networkd.c b/src/network/networkd.c
index c8f81a2ca6..2851432eff 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -20,8 +20,8 @@
#include "sd-daemon.h"
#include "capability-util.h"
-#include "networkd.h"
#include "networkd-conf.h"
+#include "networkd-manager.h"
#include "signal-util.h"
#include "user-util.h"
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index adbe09a5e1..eee91d11d2 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -2,9 +2,11 @@
#include "dhcp6-protocol.h"
#include "ethtool-util.h"
#include "netlink-internal.h"
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-macvlan.h"
-#include "networkd.h"
+#include "netdev/bond.h"
+#include "netdev/ipvlan.h"
+#include "netdev/macvlan.h"
+#include "networkd-link.h"
+#include "networkd-util.h"
#include "test-tables.h"
int main(int argc, char **argv) {
diff --git a/src/network/test-network.c b/src/network/test-network.c
index 855646173f..93184a7f88 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -20,7 +20,7 @@
#include "alloc-util.h"
#include "dhcp-lease-internal.h"
#include "network-internal.h"
-#include "networkd.h"
+#include "networkd-manager.h"
static void test_deserialize_in_addr(void) {
_cleanup_free_ struct in_addr *addresses = NULL;
diff --git a/src/network/networkd-wait-online-link.c b/src/network/wait-online/link.c
index e63ba07e90..bd8578cf93 100644
--- a/src/network/networkd-wait-online-link.c
+++ b/src/network/wait-online/link.c
@@ -21,7 +21,9 @@
#include "sd-network.h"
#include "alloc-util.h"
-#include "networkd-wait-online-link.h"
+#include "hashmap.h"
+#include "link.h"
+#include "manager.h"
#include "string-util.h"
int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
diff --git a/src/network/networkd-wait-online-link.h b/src/network/wait-online/link.h
index dc35085c55..c846e60c45 100644
--- a/src/network/networkd-wait-online-link.h
+++ b/src/network/wait-online/link.h
@@ -20,9 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct Link Link;
+#include "sd-netlink.h"
-#include "networkd-wait-online.h"
+typedef struct Link Link;
+typedef struct Manager Manager;
struct Link {
Manager *manager;
diff --git a/src/network/networkd-wait-online-manager.c b/src/network/wait-online/manager.c
index 725b3310dd..d51b0a59d6 100644
--- a/src/network/networkd-wait-online-manager.c
+++ b/src/network/wait-online/manager.c
@@ -22,10 +22,10 @@
#include <fnmatch.h>
#include "alloc-util.h"
+#include "link.h"
+#include "manager.h"
#include "netlink-util.h"
#include "network-internal.h"
-#include "networkd-wait-online-link.h"
-#include "networkd-wait-online.h"
#include "time-util.h"
#include "util.h"
diff --git a/src/network/networkd-wait-online.h b/src/network/wait-online/manager.h
index f91995c306..052f6b9780 100644
--- a/src/network/networkd-wait-online.h
+++ b/src/network/wait-online/manager.h
@@ -26,8 +26,7 @@
#include "hashmap.h"
typedef struct Manager Manager;
-
-#include "networkd-wait-online-link.h"
+typedef struct Link Link;
struct Manager {
Hashmap *links;
diff --git a/src/network/networkd-wait-online.c b/src/network/wait-online/wait-online.c
index 3220c4b7ef..268cbdb629 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/wait-online/wait-online.c
@@ -22,7 +22,7 @@
#include "sd-daemon.h"
-#include "networkd-wait-online.h"
+#include "manager.h"
#include "signal-util.h"
#include "strv.h"
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 9b9ae909c9..50d8aa049c 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -111,6 +111,8 @@
* the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/systemd/nspawn/notify"
+#define EXIT_FORCE_RESTART 133
+
typedef enum ContainerStatus {
CONTAINER_TERMINATED,
CONTAINER_REBOOTED
@@ -4002,7 +4004,7 @@ static int run(int master,
* because 133 is special-cased in the service file to reboot the container.
* otherwise → The container exited with zero status and a reboot was not requested.
*/
- if (r == 133)
+ if (r == EXIT_FORCE_RESTART)
r = EXIT_FAILURE; /* replace 133 with the general failure code */
*ret = r;
return 0; /* finito */
@@ -4017,8 +4019,8 @@ static int run(int master,
* file uses RestartForceExitStatus=133 so that this results in a full
* nspawn restart. This is necessary since we might have cgroup parameters
* set we want to have flushed out. */
- *ret = 0;
- return 133;
+ *ret = EXIT_FORCE_RESTART;
+ return 0; /* finito */
}
expose_port_flush(arg_expose_ports, exposed);
@@ -4276,8 +4278,8 @@ int main(int argc, char *argv[]) {
finish:
sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Terminating...");
+ r == 0 && ret == EXIT_FORCE_RESTART ? "STOPPING=1\nSTATUS=Restarting..." :
+ "STOPPING=1\nSTATUS=Terminating...");
if (pid > 0)
kill(pid, SIGKILL);
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 13e1f91192..e7e5c5f5a7 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -997,6 +997,7 @@ int link_load_user(Link *l) {
*ntas = NULL;
ResolveSupport s;
+ const char *p;
int r;
assert(l);
@@ -1037,48 +1038,40 @@ int link_load_user(Link *l) {
/* If we can't recognize the DNSSEC setting, then set it to invalid, so that the daemon default is used. */
l->dnssec_mode = dnssec_mode_from_string(dnssec);
- if (servers) {
- const char *p = servers;
+ for (p = servers;;) {
+ _cleanup_free_ char *word = NULL;
- for (;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, 0);
- if (r < 0)
- goto fail;
- if (r == 0)
- break;
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
- r = link_update_dns_server_one(l, word);
- if (r < 0) {
- log_debug_errno(r, "Failed to load DNS server '%s', ignoring: %m", word);
- continue;
- }
+ r = link_update_dns_server_one(l, word);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to load DNS server '%s', ignoring: %m", word);
+ continue;
}
}
- if (domains) {
- const char *p = domains;
+ for (p = domains;;) {
+ _cleanup_free_ char *word = NULL;
+ const char *n;
+ bool is_route;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- const char *n;
- bool is_route;
-
- r = extract_first_word(&p, &word, NULL, 0);
- if (r < 0)
- goto fail;
- if (r == 0)
- break;
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
- is_route = word[0] == '~';
- n = is_route ? word + 1 : word;
+ is_route = word[0] == '~';
+ n = is_route ? word + 1 : word;
- r = link_update_search_domain_one(l, n, is_route);
- if (r < 0) {
- log_debug_errno(r, "Failed to load search domain '%s', ignoring: %m", word);
- continue;
- }
+ r = link_update_search_domain_one(l, n, is_route);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to load search domain '%s', ignoring: %m", word);
+ continue;
}
}
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
index 801014caf5..13f08f8a6c 100644
--- a/src/resolve/resolved-resolv-conf.c
+++ b/src/resolve/resolved-resolv-conf.c
@@ -60,7 +60,7 @@ int manager_read_resolv_conf(Manager *m) {
return 0;
/* Is it symlinked to our own file? */
- if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
+ if (stat(PRIVATE_RESOLV_CONF, &own) >= 0 &&
st.st_dev == own.st_dev &&
st.st_ino == own.st_ino)
return 0;
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index deb75f9ae5..8d5a5c6b79 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -112,6 +112,10 @@ int main(int argc, char *argv[]) {
sd_event_get_exit_code(m->event, &r);
finish:
+ /* systemd-nspawn checks for private resov.conf to decide whether
+ or not to mount it into the container. So just delete it. */
+ (void) unlink(PRIVATE_RESOLV_CONF);
+
sd_notify(false,
"STOPPING=1\n"
"STATUS=Shutting down...");
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 35e2c8f18e..388b391342 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -62,6 +62,7 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
const char *eq, *field;
+ UnitDependency dep;
int r, rl;
assert(m);
@@ -398,9 +399,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r < 0)
return bus_log_create_error(r);
- p = eq;
-
- for (;;) {
+ for (p = eq;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
@@ -482,9 +481,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r < 0)
return bus_log_create_error(r);
- p = eq;
-
- for (;;) {
+ for (p = eq;;) {
_cleanup_free_ char *word = NULL;
int offset;
@@ -531,9 +528,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r < 0)
return bus_log_create_error(r);
- p = eq;
-
- for (;;) {
+ for (p = eq;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
@@ -578,7 +573,9 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
flags = (~flags) & NAMESPACE_FLAGS_ALL;
r = sd_bus_message_append(m, "v", "t", flags);
- } else {
+ } else if ((dep = unit_dependency_from_string(field)) >= 0)
+ r = sd_bus_message_append(m, "v", "as", 1, eq);
+ else {
log_error("Unknown assignment %s.", assignment);
return -EINVAL;
}
@@ -844,6 +841,8 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const*
log_error("Assertion failed on job for %s.", strna(d->name));
else if (streq(d->result, "unsupported"))
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
+ else if (streq(d->result, "collected"))
+ log_error("Queued job for %s was garbage collected.", strna(d->name));
else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
if (d->name) {
int q;
@@ -859,7 +858,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const*
}
}
- if (streq(d->result, "canceled"))
+ if (STR_IN_SET(d->result, "canceled", "collected"))
r = -ECANCELED;
else if (streq(d->result, "timeout"))
r = -ETIME;
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 3b8768b9a7..6aebe18fc0 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -43,6 +43,7 @@
#include "escape.h"
#include "fd-util.h"
#include "missing.h"
+#include "nsflags.h"
#include "parse-util.h"
#include "proc-cmdline.h"
#include "rlimit-util.h"
@@ -769,6 +770,23 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
char timespan[FORMAT_TIMESPAN_MAX];
print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
+ } else if (streq(name, "RestrictNamespaces")) {
+ _cleanup_free_ char *s = NULL;
+ const char *result = NULL;
+
+ if ((u & NAMESPACE_FLAGS_ALL) == 0)
+ result = "yes";
+ else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
+ result = "no";
+ else {
+ r = namespace_flag_to_string_many(u, &s);
+ if (r < 0)
+ return r;
+
+ result = s;
+ }
+
+ print_property(name, "%s", result);
} else
print_property(name, "%"PRIu64, u);
@@ -1565,3 +1583,22 @@ int bus_property_get_rlimit(
return sd_bus_message_append(reply, "t", u);
}
+
+int bus_track_add_name_many(sd_bus_track *t, char **l) {
+ int r = 0;
+ char **i;
+
+ assert(t);
+
+ /* Continues adding after failure, and returns the first failure. */
+
+ STRV_FOREACH(i, l) {
+ int k;
+
+ k = sd_bus_track_add_name(t, *i);
+ if (k < 0 && r >= 0)
+ r = k;
+ }
+
+ return r;
+}
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index 934e0b5b77..af5f133912 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -159,3 +159,5 @@ int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id,
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);
int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+
+int bus_track_add_name_many(sd_bus_track *t, char **l);
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 8bd6a51a99..525e65aedf 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -111,9 +111,8 @@ static int condition_test_kernel_command_line(Condition *c) {
return r;
equal = !!strchr(c->parameter, '=');
- p = line;
- for (;;) {
+ for (p = line;;) {
_cleanup_free_ char *word = NULL;
bool found;
diff --git a/src/shared/nsflags.c b/src/shared/nsflags.c
index 49afbede73..aeb79b131e 100644
--- a/src/shared/nsflags.c
+++ b/src/shared/nsflags.c
@@ -68,11 +68,6 @@ int namespace_flag_from_string_many(const char *name, unsigned long *ret) {
assert_se(ret);
- if (!name) {
- *ret = 0;
- return 0;
- }
-
for (;;) {
_cleanup_free_ char *word = NULL;
unsigned long f;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index af5b18c0ed..4fd8d7ba27 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -173,6 +173,8 @@ static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
static bool arg_firmware_setup = false;
static bool arg_now = false;
+static bool arg_jobs_before = false;
+static bool arg_jobs_after = false;
static int daemon_reload(int argc, char *argv[], void* userdata);
static int trivial_method(int argc, char *argv[], void *userdata);
@@ -204,6 +206,9 @@ static int acquire_bus(BusFocus focus, sd_bus **ret) {
if (arg_transport != BUS_TRANSPORT_LOCAL)
focus = BUS_FULL;
+ if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
+ focus = BUS_FULL;
+
if (!busses[focus]) {
bool user;
@@ -2192,12 +2197,49 @@ finish:
return r;
}
+static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, const char *prefix) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ const char *name, *type, *state, *job_path, *unit_path;
+ uint32_t other_id;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method,
+ &error,
+ &reply,
+ "u", id);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
+
+ r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, &state, &job_path, &unit_path)) > 0)
+ printf("%s %u (%s/%s)\n", prefix, other_id, name, type);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 0;
+}
+
struct job_info {
uint32_t id;
const char *name, *type, *state;
};
-static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipped) {
+static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
unsigned id_len, unit_len, type_len, state_len;
const struct job_info *j;
const char *on, *off;
@@ -2259,6 +2301,11 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
on, unit_len, e ? e : j->name, off,
type_len, j->type,
on, state_len, j->state, off);
+
+ if (arg_jobs_after)
+ output_waiting_jobs(bus, j->id, "GetJobAfter", "\twaiting for job");
+ if (arg_jobs_before)
+ output_waiting_jobs(bus, j->id, "GetJobBefore", "\tblocking job");
}
if (!arg_no_legend) {
@@ -2327,7 +2374,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
pager_open(arg_no_pager, false);
- output_jobs_list(jobs, c, skipped);
+ output_jobs_list(bus, jobs, c, skipped);
return 0;
}
@@ -2432,17 +2479,24 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
assert(unit_path);
STRV_FOREACH(p, lp->search_path) {
- _cleanup_free_ char *path;
+ _cleanup_free_ char *path = NULL, *lpath = NULL;
+ int r;
path = path_join(arg_root, *p, unit_name);
if (!path)
return log_oom();
- if (access(path, F_OK) == 0) {
- *unit_path = path;
- path = NULL;
- return 1;
- }
+ r = chase_symlinks(path, arg_root, &lpath);
+ if (r == -ENOENT)
+ continue;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to access path '%s': %m", path);
+
+ *unit_path = lpath;
+ lpath = NULL;
+ return 1;
}
return 0;
@@ -2509,10 +2563,6 @@ static int unit_find_paths(
if (!names)
return log_oom();
- r = set_put(names, unit_name);
- if (r < 0)
- return log_error_errno(r, "Failed to add unit name: %m");
-
r = unit_file_find_path(lp, unit_name, &path);
if (r < 0)
return r;
@@ -2530,6 +2580,10 @@ static int unit_find_paths(
}
}
+ r = set_put(names, basename(path));
+ if (r < 0)
+ return log_error_errno(r, "Failed to add unit name: %m");
+
if (dropin_paths) {
r = unit_file_find_dropin_paths(lp->search_path, NULL, names, &dropins);
if (r < 0)
@@ -6735,9 +6789,9 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
if (path) {
if (arg_full)
- r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
+ r = unit_file_create_copy(&lp, basename(path), path, &new_path, &tmp_path);
else
- r = unit_file_create_new(&lp, *name, ".d/override.conf", &new_path, &tmp_path);
+ r = unit_file_create_new(&lp, basename(path), ".d/override.conf", &new_path, &tmp_path);
} else
r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path);
if (r < 0)
@@ -7214,14 +7268,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- p = optarg;
- for (;;) {
+ for (p = optarg;;) {
_cleanup_free_ char *type = NULL;
r = extract_first_word(&p, &type, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse type: %s", optarg);
-
if (r == 0)
break;
@@ -7263,15 +7315,13 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_properties = new0(char*, 1);
if (!arg_properties)
return log_oom();
- } else {
- p = optarg;
- for (;;) {
+ } else
+ for (p = optarg;;) {
_cleanup_free_ char *prop = NULL;
r = extract_first_word(&p, &prop, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse property: %s", optarg);
-
if (r == 0)
break;
@@ -7280,7 +7330,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
prop = NULL;
}
- }
/* If the user asked for a particular
* property, show it to him, even if it is
@@ -7300,10 +7349,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
case ARG_AFTER:
arg_dependency = DEPENDENCY_AFTER;
+ arg_jobs_after = true;
break;
case ARG_BEFORE:
arg_dependency = DEPENDENCY_BEFORE;
+ arg_jobs_before = true;
break;
case ARG_SHOW_TYPES:
@@ -7457,14 +7508,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- p = optarg;
- for (;;) {
+ for (p = optarg;;) {
_cleanup_free_ char *s = NULL;
r = extract_first_word(&p, &s, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse signal: %s", optarg);
-
if (r == 0)
break;
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 9a90c2ed42..ffe7f836de 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -126,6 +126,9 @@ int sd_dhcp_client_get_client_id(
int sd_dhcp_client_set_mtu(
sd_dhcp_client *client,
uint32_t mtu);
+int sd_dhcp_client_set_client_port(
+ sd_dhcp_client *client,
+ uint16_t port);
int sd_dhcp_client_set_hostname(
sd_dhcp_client *client,
const char *hostname);
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 6029853e3e..b2ea358b8c 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -219,6 +219,18 @@ static void test_exec_systemcallerrornumber(Manager *m) {
#endif
}
+static void test_exec_restrict_namespaces(Manager *m) {
+#ifdef HAVE_SECCOMP
+ if (!is_seccomp_available())
+ return;
+
+ test(m, "exec-restrict-namespaces-no.service", 0, CLD_EXITED);
+ test(m, "exec-restrict-namespaces-yes.service", 1, CLD_EXITED);
+ test(m, "exec-restrict-namespaces-mnt.service", 0, CLD_EXITED);
+ test(m, "exec-restrict-namespaces-mnt-blacklist.service", 1, CLD_EXITED);
+#endif
+}
+
static void test_exec_systemcall_system_mode_with_user(Manager *m) {
#ifdef HAVE_SECCOMP
if (!is_seccomp_available())
@@ -435,6 +447,7 @@ int main(int argc, char *argv[]) {
test_exec_privatenetwork,
test_exec_systemcallfilter,
test_exec_systemcallerrornumber,
+ test_exec_restrict_namespaces,
test_exec_user,
test_exec_group,
test_exec_supplementary_groups,
diff --git a/src/test/test-nss.c b/src/test/test-nss.c
index c43bda5917..4ccfe75147 100644
--- a/src/test/test-nss.c
+++ b/src/test/test-nss.c
@@ -77,7 +77,8 @@ static void* open_handle(const char* dir, const char* module, int flags) {
path = strjoina("libnss_", module, ".so.2");
handle = dlopen(path, flags);
- assert_se(handle);
+ if (!handle)
+ log_error("Failed to load module %s: %s", module, dlerror());
return handle;
}
@@ -379,75 +380,158 @@ static void test_byaddr(void *handle,
puts("");
}
+static int make_addresses(struct local_address **addresses) {
+ int n;
+ size_t n_alloc;
+ _cleanup_free_ struct local_address *addrs = NULL;
+
+ n = local_addresses(NULL, 0, AF_UNSPEC, &addrs);
+ if (n < 0)
+ log_info_errno(n, "Failed to query local addresses: %m");
+
+ n_alloc = n; /* we _can_ do that */
+ if (!GREEDY_REALLOC(addrs, n_alloc, n + 3))
+ return log_oom();
+
+ addrs[n++] = (struct local_address) { .family = AF_INET,
+ .address.in = { htobe32(0x7F000001) } };
+ addrs[n++] = (struct local_address) { .family = AF_INET,
+ .address.in = { htobe32(0x7F000002) } };
+ addrs[n++] = (struct local_address) { .family = AF_INET6,
+ .address.in6 = in6addr_loopback };
+ return 0;
+}
+
+static int test_one_module(const char* dir,
+ const char *module,
+ char **names,
+ struct local_address *addresses,
+ int n_addresses) {
+ void *handle;
+ char **name;
+ int i;
+
+
+ log_info("======== %s ========", module);
+
+ handle = open_handle(streq(module, "dns") ? NULL : dir,
+ module,
+ RTLD_LAZY|RTLD_NODELETE);
+ if (!handle)
+ return -EINVAL;
+
+ STRV_FOREACH(name, names)
+ test_byname(handle, module, *name);
+
+ for (i = 0; i < n_addresses; i++)
+ test_byaddr(handle, module,
+ &addresses[i].address,
+ FAMILY_ADDRESS_SIZE(addresses[i].family),
+ addresses[i].family);
+
+ log_info(" ");
+ dlclose(handle);
+ return 0;
+}
+
+static int parse_argv(int argc, char **argv,
+ char ***the_modules,
+ char ***the_names,
+ struct local_address **the_addresses, int *n_addresses) {
+
+ int r, n = 0;
+ _cleanup_strv_free_ char **modules = NULL, **names = NULL;
+ _cleanup_free_ struct local_address *addrs = NULL;
+ size_t n_allocated = 0;
+
+ if (argc > 1)
+ modules = strv_new(argv[1], NULL);
+ else
+ modules = strv_new(
#ifdef HAVE_MYHOSTNAME
-# define MODULE1 "myhostname\0"
-#else
-# define MODULE1
+ "myhostname",
#endif
#ifdef HAVE_RESOLVED
-# define MODULE2 "resolve\0"
-#else
-# define MODULE2
+ "resolve",
#endif
#ifdef HAVE_MACHINED
-# define MODULE3 "mymachines\0"
-#else
-# define MODULE3
+ "mymachines",
#endif
-#define MODULE4 "dns\0"
+ "dns",
+ NULL);
+ if (!modules)
+ return -ENOMEM;
+
+ if (argc > 2) {
+ char **name;
+ int family;
+ union in_addr_union address;
+
+ STRV_FOREACH(name, argv + 2) {
+ r = in_addr_from_string_auto(*name, &family, &address);
+ if (r < 0) {
+ /* assume this is a name */
+ r = strv_extend(&names, *name);
+ if (r < 0)
+ return r;
+ } else {
+ if (!GREEDY_REALLOC0(addrs, n_allocated, n + 1))
+ return -ENOMEM;
+
+ addrs[n++] = (struct local_address) { .family = family,
+ .address = address };
+ }
+ }
+ } else {
+ _cleanup_free_ char *hostname;
-int main(int argc, char **argv) {
- _cleanup_free_ char *dir = NULL, *hostname = NULL;
- const char *module;
+ hostname = gethostname_malloc();
+ if (!hostname)
+ return -ENOMEM;
- const uint32_t local_address_ipv4 = htobe32(0x7F000001);
- const uint32_t local_address_ipv4_2 = htobe32(0x7F000002);
+ names = strv_new("localhost", "gateway", "foo_no_such_host", hostname, NULL);
+ if (!names)
+ return -ENOMEM;
+
+ n = make_addresses(&addrs);
+ if (n < 0)
+ return n;
+ }
+
+ *the_modules = modules;
+ *the_names = names;
+ modules = names = NULL;
+ *the_addresses = addrs;
+ *n_addresses = n;
+ addrs = NULL;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ _cleanup_free_ char *dir = NULL;
+ _cleanup_strv_free_ char **modules = NULL, **names = NULL;
_cleanup_free_ struct local_address *addresses = NULL;
int n_addresses;
+ char **module;
+ int r;
log_set_max_level(LOG_INFO);
log_parse_environment();
- dir = dirname_malloc(argv[0]);
- assert_se(dir);
-
- hostname = gethostname_malloc();
- assert_se(hostname);
-
- n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
- if (n_addresses < 0) {
- log_info_errno(n_addresses, "Failed to query local addresses: %m");
- n_addresses = 0;
+ r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse arguments: %m");
+ return EXIT_FAILURE;
}
- NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) {
- void *handle;
- const char *name;
- int i;
-
- log_info("======== %s ========", module);
-
- handle = open_handle(streq(module, "dns") ? NULL : dir,
- module,
- RTLD_LAZY|RTLD_NODELETE);
- NULSTR_FOREACH(name, "localhost\0" "gateway\0" "foo_no_such_host\0")
- test_byname(handle, module, name);
-
- test_byname(handle, module, hostname);
-
- test_byaddr(handle, module, &local_address_ipv4, sizeof local_address_ipv4, AF_INET);
- test_byaddr(handle, module, &local_address_ipv4_2, sizeof local_address_ipv4_2, AF_INET);
- test_byaddr(handle, module, &in6addr_loopback, sizeof in6addr_loopback, AF_INET6);
-
- for (i = 0; i < n_addresses; i++)
- test_byaddr(handle, module,
- &addresses[i].address,
- FAMILY_ADDRESS_SIZE(addresses[i].family),
- addresses[i].family);
-
- dlclose(handle);
+ dir = dirname_malloc(argv[0]);
+ if (!dir)
+ return EXIT_FAILURE;
- log_info(" ");
+ STRV_FOREACH(module, modules) {
+ r = test_one_module(dir, *module, names, addresses, n_addresses);
+ if (r < 0)
+ return EXIT_FAILURE;
}
return EXIT_SUCCESS;
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index a455652a27..6a6c1577c6 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -330,11 +330,13 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
tmx.esterror = 0;
log_debug(" adjust (slew): %+.3f sec", offset);
} else {
- tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET;
+ tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET | ADJ_MAXERROR | ADJ_ESTERROR;
/* ADJ_NANO uses nanoseconds in the microseconds field */
tmx.time.tv_sec = (long)offset;
tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC;
+ tmx.maxerror = 0;
+ tmx.esterror = 0;
/* the kernel expects -0.3s as {-1, 7000.000.000} */
if (tmx.time.tv_usec < 0) {
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
index 708a665576..d7edbb396b 100644
--- a/src/udev/net/ethtool-util.c
+++ b/src/udev/net/ethtool-util.c
@@ -29,6 +29,7 @@
#include "string-table.h"
#include "strxcpyx.h"
#include "util.h"
+#include "missing.h"
static const char* const duplex_table[_DUP_MAX] = {
[DUP_FULL] = "full",
@@ -323,3 +324,211 @@ int ethtool_set_features(int *fd, const char *ifname, NetDevFeature *features) {
return 0;
}
+
+static int get_glinksettings(int *fd, struct ifreq *ifr, struct ethtool_link_usettings **g) {
+ struct ecmd {
+ struct ethtool_link_settings req;
+ __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+ } ecmd = {
+ .req.cmd = ETHTOOL_GLINKSETTINGS,
+ };
+ struct ethtool_link_usettings *u;
+ unsigned offset;
+ int r;
+
+ /* The interaction user/kernel via the new API requires a small ETHTOOL_GLINKSETTINGS
+ handshake first to agree on the length of the link mode bitmaps. If kernel doesn't
+ agree with user, it returns the bitmap length it is expecting from user as a negative
+ length (and cmd field is 0). When kernel and user agree, kernel returns valid info in
+ all fields (ie. link mode length > 0 and cmd is ETHTOOL_GLINKSETTINGS). Based on
+ https://github.com/torvalds/linux/commit/3f1ac7a700d039c61d8d8b99f28d605d489a60cf
+ */
+
+ ifr->ifr_data = (void *) &ecmd;
+
+ r = ioctl(*fd, SIOCETHTOOL, ifr);
+ if (r < 0)
+ return -errno;
+
+ if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+ return -ENOTSUP;
+
+ ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
+
+ ifr->ifr_data = (void *) &ecmd;
+
+ r = ioctl(*fd, SIOCETHTOOL, ifr);
+ if (r < 0)
+ return -errno;
+
+ if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+ return -ENOTSUP;
+
+ u = new0(struct ethtool_link_usettings , 1);
+ if (!u)
+ return -ENOMEM;
+
+ memcpy(&u->base, &ecmd.req, sizeof(struct ethtool_link_settings));
+
+ offset = 0;
+ memcpy(u->link_modes.supported, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
+
+ offset += ecmd.req.link_mode_masks_nwords;
+ memcpy(u->link_modes.advertising, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
+
+ offset += ecmd.req.link_mode_masks_nwords;
+ memcpy(u->link_modes.lp_advertising, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
+
+ *g = u;
+
+ return 0;
+}
+
+static int get_gset(int *fd, struct ifreq *ifr, struct ethtool_link_usettings **u) {
+ struct ethtool_link_usettings *e;
+ struct ethtool_cmd ecmd = {
+ .cmd = ETHTOOL_GSET,
+ };
+ int r;
+
+ ifr->ifr_data = (void *) &ecmd;
+
+ r = ioctl(*fd, SIOCETHTOOL, ifr);
+ if (r < 0)
+ return -errno;
+
+ e = new0(struct ethtool_link_usettings, 1);
+ if (!e)
+ return -ENOMEM;
+
+ e->base.cmd = ETHTOOL_GSET;
+
+ e->base.link_mode_masks_nwords = 1;
+ e->base.speed = ethtool_cmd_speed(&ecmd);
+ e->base.duplex = ecmd.duplex;
+ e->base.port = ecmd.port;
+ e->base.phy_address = ecmd.phy_address;
+ e->base.autoneg = ecmd.autoneg;
+ e->base.mdio_support = ecmd.mdio_support;
+
+ e->link_modes.supported[0] = ecmd.supported;
+ e->link_modes.advertising[0] = ecmd.advertising;
+ e->link_modes.lp_advertising[0] = ecmd.lp_advertising;
+
+ *u = e;
+
+ return 0;
+}
+
+static int set_slinksettings(int *fd, struct ifreq *ifr, const struct ethtool_link_usettings *u) {
+ struct {
+ struct ethtool_link_settings req;
+ __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+ } ecmd = {
+ .req.cmd = ETHTOOL_SLINKSETTINGS,
+ };
+ unsigned int offset;
+ int r;
+
+ if (u->base.cmd != ETHTOOL_GLINKSETTINGS || u->base.link_mode_masks_nwords <= 0)
+ return -EINVAL;
+
+ offset = 0;
+ memcpy(&ecmd.link_mode_data[offset], u->link_modes.supported, 4 * ecmd.req.link_mode_masks_nwords);
+
+ offset += ecmd.req.link_mode_masks_nwords;
+ memcpy(&ecmd.link_mode_data[offset], u->link_modes.advertising, 4 * ecmd.req.link_mode_masks_nwords);
+
+ offset += ecmd.req.link_mode_masks_nwords;
+ memcpy(&ecmd.link_mode_data[offset], u->link_modes.lp_advertising, 4 * ecmd.req.link_mode_masks_nwords);
+
+ ifr->ifr_data = (void *) &ecmd;
+
+ r = ioctl(*fd, SIOCETHTOOL, ifr);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int set_sset(int *fd, struct ifreq *ifr, const struct ethtool_link_usettings *u) {
+ struct ethtool_cmd ecmd = {
+ .cmd = ETHTOOL_SSET,
+ };
+ int r;
+
+ if (u->base.cmd != ETHTOOL_GSET || u->base.link_mode_masks_nwords <= 0)
+ return -EINVAL;
+
+ ecmd.supported = u->link_modes.supported[0];
+ ecmd.advertising = u->link_modes.advertising[0];
+ ecmd.lp_advertising = u->link_modes.lp_advertising[0];
+
+ ethtool_cmd_speed_set(&ecmd, u->base.speed);
+
+ ecmd.duplex = u->base.duplex;
+ ecmd.port = u->base.port;
+ ecmd.phy_address = u->base.phy_address;
+ ecmd.autoneg = u->base.autoneg;
+ ecmd.mdio_support = u->base.mdio_support;
+
+ ifr->ifr_data = (void *) &ecmd;
+
+ r = ioctl(*fd, SIOCETHTOOL, ifr);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+/* If autonegotiation is disabled, the speed and duplex represent the fixed link
+ * mode and are writable if the driver supports multiple link modes. If it is
+ * enabled then they are read-only. If the link is up they represent the negotiated
+ * link mode; if the link is down, the speed is 0, %SPEED_UNKNOWN or the highest
+ * enabled speed and @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
+ */
+
+int ethtool_set_glinksettings(int *fd, const char *ifname, unsigned int speed, Duplex duplex, int autonegotiation) {
+ _cleanup_free_ struct ethtool_link_usettings *u = NULL;
+ struct ifreq ifr = {};
+ int r;
+
+ if (autonegotiation != 0) {
+ log_info("link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.");
+ return 0;
+ }
+
+ if (*fd < 0) {
+ r = ethtool_connect(fd);
+ if (r < 0)
+ return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
+ }
+
+ strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
+
+ r = get_glinksettings(fd, &ifr, &u);
+ if (r < 0) {
+
+ r = get_gset(fd, &ifr, &u);
+ if (r < 0)
+ return log_warning_errno(r, "link_config: Cannot get device settings for %s : %m", ifname);
+ }
+
+ if (speed)
+ u->base.speed = speed;
+
+ if (duplex != _DUP_INVALID)
+ u->base.duplex = duplex;
+
+ u->base.autoneg = autonegotiation;
+
+ if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
+ r = set_slinksettings(fd, &ifr, u);
+ else
+ r = set_sset(fd, &ifr, u);
+
+ if (r < 0)
+ return log_warning_errno(r, "link_config: Cannot set device settings for %s : %m", ifname);
+
+ return r;
+}
diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h
index 0744164653..75d6af396b 100644
--- a/src/udev/net/ethtool-util.h
+++ b/src/udev/net/ethtool-util.h
@@ -20,6 +20,9 @@
***/
#include <macro.h>
+#include <linux/ethtool.h>
+
+#include "missing.h"
/* we can't use DUPLEX_ prefix, as it
* clashes with <linux/ethtool.h> */
@@ -48,12 +51,27 @@ typedef enum NetDevFeature {
_NET_DEV_FEAT_INVALID = -1
} NetDevFeature;
+
+#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX)
+
+/* layout of the struct passed from/to userland */
+struct ethtool_link_usettings {
+ struct ethtool_link_settings base;
+
+ struct {
+ uint32_t supported[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+ uint32_t advertising[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+ uint32_t lp_advertising[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+ } link_modes;
+};
+
int ethtool_connect(int *ret);
int ethtool_get_driver(int *fd, const char *ifname, char **ret);
int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex);
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
int ethtool_set_features(int *fd, const char *ifname, NetDevFeature *features);
+int ethtool_set_glinksettings(int *fd, const char *ifname, unsigned int speed, Duplex duplex, int autoneg);
const char *duplex_to_string(Duplex d) _const_;
Duplex duplex_from_string(const char *d) _pure_;
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index f8b85cbd13..78e551df22 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -34,6 +34,7 @@ Link.Alias, config_parse_ifalias, 0,
Link.MTUBytes, config_parse_iec_size, 0, offsetof(link_config, mtu)
Link.BitsPerSecond, config_parse_si_size, 0, offsetof(link_config, speed)
Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex)
+Link.AutoNegotiation, config_parse_tristate, 0, offsetof(link_config, autonegotiation)
Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol)
Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO])
Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO])
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index ece9248c2a..1dca375279 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -167,8 +167,9 @@ static int load_link(link_config_ctx *ctx, const char *filename) {
link->mac_policy = _MACPOLICY_INVALID;
link->wol = _WOL_INVALID;
link->duplex = _DUP_INVALID;
+ link->autonegotiation = -1;
- memset(&link->features, -1, _NET_DEV_FEAT_MAX);
+ memset(&link->features, -1, sizeof(link->features));
r = config_parse(NULL, filename, file,
"Match\0Link\0Ethernet\0",
@@ -202,9 +203,9 @@ static bool enable_name_policy(void) {
}
int link_config_load(link_config_ctx *ctx) {
- int r;
_cleanup_strv_free_ char **files;
char **f;
+ int r;
link_configs_free(ctx);
@@ -364,11 +365,12 @@ static int get_mac(struct udev_device *device, bool want_random,
int link_config_apply(link_config_ctx *ctx, link_config *config,
struct udev_device *device, const char **name) {
- const char *old_name;
- const char *new_name = NULL;
+ bool respect_predictable = false;
struct ether_addr generated_mac;
struct ether_addr *mac = NULL;
- bool respect_predictable = false;
+ const char *new_name = NULL;
+ const char *old_name;
+ unsigned speed;
int r, ifindex;
assert(ctx);
@@ -380,11 +382,19 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
if (!old_name)
return -EINVAL;
- r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex);
- if (r < 0)
- log_warning_errno(r, "Could not set speed or duplex of %s to %zu Mbps (%s): %m",
- old_name, config->speed / 1024,
- duplex_to_string(config->duplex));
+
+ speed = DIV_ROUND_UP(config->speed, 1000000);
+
+ r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name, speed, config->duplex, config->autonegotiation);
+ if (r < 0) {
+
+ if (r == -EOPNOTSUPP)
+ r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
+
+ if (r < 0)
+ log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
+ old_name, speed, duplex_to_string(config->duplex));
+ }
r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
if (r < 0)
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 91cc0357c4..a99060d943 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -69,6 +69,7 @@ struct link_config {
size_t mtu;
size_t speed;
Duplex duplex;
+ int autonegotiation;
WakeOnLan wol;
NetDevFeature features[_NET_DEV_FEAT_MAX];
diff --git a/test/test-execute/exec-restrict-namespaces-mnt-blacklist.service b/test/test-execute/exec-restrict-namespaces-mnt-blacklist.service
new file mode 100644
index 0000000000..ab909cbd94
--- /dev/null
+++ b/test/test-execute/exec-restrict-namespaces-mnt-blacklist.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test RestrictNamespaces=~mnt
+
+[Service]
+RestrictNamespaces=~mnt
+ExecStart=/bin/sh -x -c 'unshare -m'
+Type=oneshot
diff --git a/test/test-execute/exec-restrict-namespaces-mnt.service b/test/test-execute/exec-restrict-namespaces-mnt.service
new file mode 100644
index 0000000000..1aeed72717
--- /dev/null
+++ b/test/test-execute/exec-restrict-namespaces-mnt.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test RestrictNamespaces=mnt
+
+[Service]
+RestrictNamespaces=mnt
+ExecStart=/bin/sh -x -c 'unshare -m'
+Type=oneshot
diff --git a/test/test-execute/exec-restrict-namespaces-no.service b/test/test-execute/exec-restrict-namespaces-no.service
new file mode 100644
index 0000000000..33500302d2
--- /dev/null
+++ b/test/test-execute/exec-restrict-namespaces-no.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test RestrictNamespaces=no
+
+[Service]
+RestrictNamespaces=no
+ExecStart=/bin/sh -x -c 'unshare -m -u -i -n -p -f'
+Type=oneshot
diff --git a/test/test-execute/exec-restrict-namespaces-yes.service b/test/test-execute/exec-restrict-namespaces-yes.service
new file mode 100644
index 0000000000..3fe70e2bea
--- /dev/null
+++ b/test/test-execute/exec-restrict-namespaces-yes.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test RestrictNamespaces=yes
+
+[Service]
+RestrictNamespaces=yes
+ExecStart=/bin/sh -x -c 'unshare -m'
+Type=oneshot
diff --git a/test/test-functions b/test/test-functions
index 2a21a64c5c..c0128b8b00 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -5,13 +5,14 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH
LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE" = "debian" ]] && echo yes)
+LOOKS_LIKE_ARCH=$(source /etc/os-release && [[ "$ID" = "arch" ]] && echo yes)
KERNEL_VER=${KERNEL_VER-$(uname -r)}
KERNEL_MODS="/lib/modules/$KERNEL_VER/"
QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out
FSTYPE="${FSTYPE:-ext3}"
-UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-no}"
+UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}"
if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
@@ -58,15 +59,43 @@ run_qemu() {
&& KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux"
fi
+ if [[ ! "$KERNEL_BIN" ]]; then
+ if [[ "$LOOKS_LIKE_ARCH" ]]; then
+ KERNEL_BIN=/boot/vmlinuz-linux
+ else
+ KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER
+ fi
+ fi
+
default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img
default_debian_initrd=/boot/initrd.img-${KERNEL_VER}
- [ "$KERNEL_BIN" ] || KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER
- [ "$INITRD" ] || { [ -e "$default_fedora_initrd" ] && INITRD=$default_fedora_initrd; }
- [ "$INITRD" ] || { [ "$LOOKS_LIKE_DEBIAN" ] && [ -e "$default_debian_initrd" ] && INITRD=$default_debian_initrd; }
+ default_arch_initrd=/boot/initramfs-linux.img
+ if [[ ! "$INITRD" ]]; then
+ if [[ -e "$default_fedora_initrd" ]]; then
+ INITRD="$default_fedora_initrd"
+ elif [[ "$LOOKS_LIKE_DEBIAN" && -e "$default_debian_initrd" ]]; then
+ INITRD="$default_debian_initrd"
+ elif [[ "$LOOKS_LIKE_ARCH" && -e "$default_arch_initrd" ]]; then
+ INITRD="$default_arch_initrd"
+ fi
+ fi
+
[ "$QEMU_SMP" ] || QEMU_SMP=1
find_qemu_bin || return 1
+ local _cgroup_args
+ if [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ]]; then
+ _cgroup_args="systemd.unified_cgroup_hierarchy=yes"
+ elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
+ _cgroup_args="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=yes"
+ elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
+ _cgroup_args="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=no"
+ elif [[ "$UNIFIED_CGROUP_HIERARCHY" != "default" ]]; then
+ dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
+ exit 1
+ fi
+
KERNEL_APPEND="root=/dev/sda1 \
raid=noautodetect \
loglevel=2 \
@@ -74,7 +103,7 @@ init=$ROOTLIBDIR/systemd \
ro \
console=ttyS0 \
selinux=0 \
-systemd.unified_cgroup_hierarchy=$UNIFIED_CGROUP_HIERARCHY \
+$_cgroup_args \
$KERNEL_APPEND \
"
@@ -118,7 +147,17 @@ run_nspawn() {
_nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
fi
- _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
+ if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
+ dwarn "nspawn doesn't support UNIFIED_CGROUP_HIERARCHY=hybrid, skipping"
+ exit
+ elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" || "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
+ _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
+ elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
+ _nspawn_cmd="env --unset=UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
+ else
+ dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
+ exit 1
+ fi
(set -x; $_nspawn_cmd)
rc=$?
diff --git a/units/sys-fs-fuse-connections.mount b/units/sys-fs-fuse-connections.mount
index e940beb09f..336b5f6277 100644
--- a/units/sys-fs-fuse-connections.mount
+++ b/units/sys-fs-fuse-connections.mount
@@ -12,6 +12,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
DefaultDependencies=no
ConditionPathExists=/sys/fs/fuse/connections
ConditionCapability=CAP_SYS_ADMIN
+ConditionVirtualization=!private-users
After=systemd-modules-load.service
Before=sysinit.target