summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CODING_STYLE5
-rw-r--r--Makefile.am21
-rw-r--r--NEWS165
-rw-r--r--TODO11
-rw-r--r--catalog/systemd.hr.catalog2
-rw-r--r--configure.ac9
-rw-r--r--man/logind.conf.xml16
-rw-r--r--man/machinectl.xml12
-rw-r--r--man/networkd.conf.xml81
-rw-r--r--man/systemd.automount.xml15
-rw-r--r--man/systemd.mount.xml14
-rw-r--r--man/systemd.network.xml53
-rw-r--r--man/systemd.slice.xml3
-rw-r--r--man/systemd.socket.xml15
-rw-r--r--man/systemd.swap.xml13
-rw-r--r--man/systemd.unit.xml17
-rw-r--r--po/it.po138
-rw-r--r--src/basic/architecture.c3
-rw-r--r--src/basic/architecture.h4
-rw-r--r--src/basic/copy.c50
-rw-r--r--src/basic/copy.h1
-rw-r--r--src/basic/fileio.c2
-rw-r--r--src/basic/hashmap.c10
-rw-r--r--src/basic/log.c6
-rw-r--r--src/basic/process-util.c12
-rw-r--r--src/basic/process-util.h4
-rw-r--r--src/basic/socket-util.h11
-rw-r--r--src/basic/strbuf.c3
-rw-r--r--src/basic/virt.c2
-rw-r--r--src/cgroups-agent/cgroups-agent.c48
-rw-r--r--src/core/automount.c120
-rw-r--r--src/core/automount.h4
-rw-r--r--src/core/busname.c11
-rw-r--r--src/core/busname.h1
-rw-r--r--src/core/cgroup.c6
-rw-r--r--src/core/dbus-socket.c2
-rw-r--r--src/core/dbus.c75
-rw-r--r--src/core/dbus.h2
-rw-r--r--src/core/device.c2
-rw-r--r--src/core/execute.c2
-rw-r--r--src/core/load-fragment.c29
-rw-r--r--src/core/manager.c164
-rw-r--r--src/core/manager.h3
-rw-r--r--src/core/mount.c32
-rw-r--r--src/core/mount.h1
-rw-r--r--src/core/path.c8
-rw-r--r--src/core/path.h1
-rw-r--r--src/core/scope.c2
-rw-r--r--src/core/service.c9
-rw-r--r--src/core/service.h1
-rw-r--r--src/core/slice.c2
-rw-r--r--src/core/socket.c62
-rw-r--r--src/core/socket.h1
-rw-r--r--src/core/swap.c13
-rw-r--r--src/core/swap.h1
-rw-r--r--src/core/timer.c10
-rw-r--r--src/core/timer.h1
-rw-r--r--src/core/unit.c51
-rw-r--r--src/core/unit.h8
-rw-r--r--src/coredump/coredump.c2
-rw-r--r--src/fsck/fsck.c2
-rw-r--r--src/fstab-generator/fstab-generator.c1
-rw-r--r--src/import/importd.c2
-rw-r--r--src/import/pull-common.c2
-rw-r--r--src/journal/journal-file.c4
-rw-r--r--src/journal/journal-send.c14
-rw-r--r--src/journal/journald-native.c14
-rw-r--r--src/journal/journald-server.c2
-rw-r--r--src/journal/journald-stream.c13
-rw-r--r--src/journal/journald-syslog.c36
-rw-r--r--src/journal/sd-journal.c2
-rw-r--r--src/libsystemd-network/dhcp-identifier.c31
-rw-r--r--src/libsystemd-network/dhcp-identifier.h42
-rw-r--r--src/libsystemd-network/network-internal.c77
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c181
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c58
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c2
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c4
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c6
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c28
-rw-r--r--src/locale/language-fallback-map4
-rw-r--r--src/login/logind-dbus.c49
-rw-r--r--src/login/logind-gperf.gperf2
-rw-r--r--src/login/logind-inhibit.c2
-rw-r--r--src/login/logind-seat-dbus.c2
-rw-r--r--src/login/logind-session.c4
-rw-r--r--src/login/logind-user-dbus.c2
-rw-r--r--src/login/logind.c6
-rw-r--r--src/login/logind.conf.in2
-rw-r--r--src/login/logind.h2
-rw-r--r--src/login/pam_systemd.c2
-rw-r--r--src/machine/image-dbus.c75
-rw-r--r--src/machine/machine-dbus.c66
-rw-r--r--src/machine/machine.c24
-rw-r--r--src/machine/machine.h20
-rw-r--r--src/machine/machinectl.c69
-rw-r--r--src/machine/machined.c8
-rw-r--r--src/machine/machined.h4
-rw-r--r--src/machine/operation.c131
-rw-r--r--src/machine/operation.h47
-rw-r--r--src/network/networkd-address-pool.h4
-rw-r--r--src/network/networkd-address.c48
-rw-r--r--src/network/networkd-address.h5
-rw-r--r--src/network/networkd-conf.c88
-rw-r--r--src/network/networkd-conf.h29
-rw-r--r--src/network/networkd-dhcp4.c26
-rw-r--r--src/network/networkd-dhcp6.c18
-rw-r--r--src/network/networkd-fdb.h8
-rw-r--r--src/network/networkd-gperf.gperf4
-rw-r--r--src/network/networkd-ipv4ll.c2
-rw-r--r--src/network/networkd-link.c38
-rw-r--r--src/network/networkd-link.h15
-rw-r--r--src/network/networkd-lldp-tx.c5
-rw-r--r--src/network/networkd-manager.c2
-rw-r--r--src/network/networkd-ndisc.c2
-rw-r--r--src/network/networkd-netdev-bond.c1
-rw-r--r--src/network/networkd-netdev-bond.h8
-rw-r--r--src/network/networkd-netdev-bridge.c1
-rw-r--r--src/network/networkd-netdev-bridge.h7
-rw-r--r--src/network/networkd-netdev-dummy.h7
-rw-r--r--src/network/networkd-netdev-gperf.gperf12
-rw-r--r--src/network/networkd-netdev-ipvlan.h7
-rw-r--r--src/network/networkd-netdev-macvlan.h2
-rw-r--r--src/network/networkd-netdev-tunnel.h17
-rw-r--r--src/network/networkd-netdev-tuntap.c7
-rw-r--r--src/network/networkd-netdev-tuntap.h2
-rw-r--r--src/network/networkd-netdev-veth.h1
-rw-r--r--src/network/networkd-netdev-vlan.h1
-rw-r--r--src/network/networkd-netdev-vxlan.c2
-rw-r--r--src/network/networkd-netdev-vxlan.h1
-rw-r--r--src/network/networkd-netdev.h55
-rw-r--r--src/network/networkd-network-gperf.gperf6
-rw-r--r--src/network/networkd-network.c2
-rw-r--r--src/network/networkd-network.h26
-rw-r--r--src/network/networkd-route.c64
-rw-r--r--src/network/networkd-route.h4
-rw-r--r--src/network/networkd.h34
-rw-r--r--src/network/test-networkd-conf.c91
-rw-r--r--src/reply-password/reply-password.c8
-rw-r--r--src/resolve/resolved-dns-query.c2
-rw-r--r--src/resolve/resolved-dns-transaction.c65
-rw-r--r--src/shared/ask-password-api.c2
-rw-r--r--src/shared/install.c219
-rw-r--r--src/shared/install.h3
-rw-r--r--src/shared/machine-image.c26
-rw-r--r--src/socket-proxy/socket-proxyd.c17
-rw-r--r--src/systemctl/systemctl.c40
-rw-r--r--src/systemd/sd-dhcp-client.h78
-rw-r--r--src/systemd/sd-dhcp6-client.h61
-rw-r--r--src/systemd/sd-netlink.h2
-rw-r--r--src/test/test-install-root.c48
-rw-r--r--src/test/test-socket-util.c17
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c7
-rw-r--r--src/udev/udev-ctrl.c2
-rw-r--r--src/udev/udev-rules.c14
l---------[-rw-r--r--]test/TEST-06-SELINUX/Makefile11
l---------[-rw-r--r--]test/TEST-08-ISSUE-2730/Makefile11
l---------test/TEST-10-ISSUE-2467/Makefile1
-rwxr-xr-xtest/TEST-10-ISSUE-2467/test.sh88
l---------test/TEST-11-ISSUE-3166/Makefile1
-rwxr-xr-xtest/TEST-11-ISSUE-3166/test.sh91
l---------test/TEST-12-ISSUE-3171/Makefile1
-rwxr-xr-xtest/TEST-12-ISSUE-3171/test.sh106
-rw-r--r--tmpfiles.d/systemd.conf.m430
165 files changed, 2786 insertions, 1232 deletions
diff --git a/.gitignore b/.gitignore
index c7eb14452d..091b400182 100644
--- a/.gitignore
+++ b/.gitignore
@@ -235,6 +235,7 @@
/test-ndisc-rs
/test-netlink
/test-netlink-manual
+/test-networkd-conf
/test-network
/test-network-tables
/test-ns
diff --git a/CODING_STYLE b/CODING_STYLE
index c2b2e56d5d..b689355c9a 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -240,6 +240,11 @@
unlink("/foo/bar/baz");
+ Don't cast function calls to (void) that return no error
+ conditions. Specifically, the various xyz_unref() calls that return a NULL
+ object shouldn't be cast to (void), since not using the return value does not
+ hide any errors.
+
- Don't invoke exit(), ever. It is not replacement for proper error
handling. Please escalate errors up your call chain, and use normal
"return" to exit from the main function of a process. If you
diff --git a/Makefile.am b/Makefile.am
index b323de55c6..ee9e91a339 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4942,7 +4942,9 @@ libmachine_core_la_SOURCES = \
src/machine/machine-dbus.c \
src/machine/machine-dbus.h \
src/machine/image-dbus.c \
- src/machine/image-dbus.h
+ src/machine/image-dbus.h \
+ src/machine/operation.c \
+ src/machine/operation.h
libmachine_core_la_LIBADD = \
libshared.la
@@ -5513,6 +5515,12 @@ networkctl_LDADD = \
dist_bashcompletion_data += \
shell-completion/bash/networkctl
+test_networkd_conf_SOURCES = \
+ src/network/test-networkd-conf.c
+
+test_networkd_conf_LDADD = \
+ libnetworkd-core.la
+
test_network_SOURCES = \
src/network/test-network.c
@@ -5538,6 +5546,7 @@ test_network_tables_LDADD += \
endif
tests += \
+ test-networkd-conf \
test-network \
test-network-tables
@@ -5827,6 +5836,16 @@ EXTRA_DIST += \
test/TEST-07-ISSUE-1981/Makefile \
test/TEST-07-ISSUE-1981/test-segfault.sh \
test/TEST-07-ISSUE-1981/test.sh \
+ test/TEST-08-ISSUE-2730/Makefile \
+ test/TEST-08-ISSUE-2730/test.sh \
+ test/TEST-09-ISSUE-2691/Makefile \
+ test/TEST-09-ISSUE-2691/test.sh \
+ test/TEST-10-ISSUE-2467/Makefile \
+ test/TEST-10-ISSUE-2467/test.sh \
+ test/TEST-11-ISSUE-3166/Makefile \
+ test/TEST-11-ISSUE-3166/test.sh \
+ test/TEST-12-ISSUE-3171/Makefile \
+ test/TEST-12-ISSUE-3171/test.sh \
test/test-functions
EXTRA_DIST += \
diff --git a/NEWS b/NEWS
index 16ea7b7290..8f1cde01e8 100644
--- a/NEWS
+++ b/NEWS
@@ -17,25 +17,29 @@ CHANGES WITH 230 in spe:
might be systems we do not cover yet. Hence: please help us testing
the DNSSEC code, leave this on where you can, report back, but then
again don't consider turning this on in your stable, LTS or
- production release just yet.
+ production release just yet. (Note that you have to enable
+ nss-resolve in /etc/nsswitch.conf, to actually use systemd-resolved
+ and its DNSSEC mode for host name resolution from local
+ applications.)
* systemd-resolve conveniently resolves DANE records with the --tlsa
- option and OPENPGPKEY records with the --openpgp option.
+ option and OPENPGPKEY records with the --openpgp option. It also
+ supports dumping raw DNS record data via the new --raw= switch now.
* systemd-logind will now by default terminate user processes that are
part of the user session scope unit (session-XX.scope) when the user
- logs out. This behaviour is controlled by the
- KillUserProcesses=yes|no setting in logind.conf, and previous default
- of "no" is now changed to "yes". This means that user sessions will
- be properly cleaned up after, but additional steps are necessary to
- allow intentionally long-running processes to survive logout.
+ logs out. This behaviour is controlled by the KillUserProcesses=
+ setting in logind.conf, and the previous default of "no" is now
+ changed to "yes". This means that user sessions will be properly
+ cleaned up after, but additional steps are necessary to allow
+ intentionally long-running processes to survive logout.
While the user is logged in at least once, user@.service is running,
and any service that should survive the end of any individual login
session can be started at a user service or scope using systemd-run.
- systemd-run(1) man page has been extended with an example which
- shows how to run screen in a scope unit underneath user@.service.
- The same command works for tmux.
+ systemd-run(1) man page has been extended with an example which shows
+ how to run screen in a scope unit underneath user@.service. The same
+ command works for tmux.
After the user logs out of all sessions, user@.service will be
terminated too, by default, unless the user has "lingering" enabled.
@@ -45,36 +49,38 @@ CHANGES WITH 230 in spe:
set lingering for themselves without authentication.
Previous defaults can be restored at compile time by the
- --without-kill-user-processes option.
+ --without-kill-user-processes option to "configure".
* The unified cgroup hierarchy added in Linux 4.5 is now supported.
- Use systemd.unified_cgroup_hierarchy=1 on the kernel command line
- to enable.
+ Use systemd.unified_cgroup_hierarchy=1 on the kernel command line to
+ enable.
+
WARNING: it is not possible to use previous systemd versions with
systemd.unified_cgroup_hierarchy=1 and the new kernel. Therefore it
is necessary to also update systemd in the initramfs if using the
- unified hierarchy. Updated selinux policy is also required.
-
- * LLDP support has been extended, and both passive (receive-only)
- and active (sender) modes are supported. Passive mode
- ("routers-only") is enabled by default in systemd-networkd.
- Active LLDP mode is enabled by default for containers on the
- internal network.
- "networkctl lldp" can be used to list information gathered.
+ unified hierarchy. An updated SELinux policy is also required.
- * Headers for LLDP support (sd-lldp.h) are now public.
+ * LLDP support has been extended, and both passive (receive-only) and
+ active (sender) modes are supported. Passive mode ("routers-only") is
+ enabled by default in systemd-networkd. Active LLDP mode is enabled
+ by default for containers on the internal network. The "networkctl
+ lldp" command may be used to list information gathered. "networkctl
+ status" will also show basic LLDP information on connected peers now.
- * The Unique Identifier sent in DHCP requests can be configured.
+ * The IAID and DUID unique identifier sent in DHCP requests may now be
+ configured for the system and each .network file managed by
+ systemd-networkd.
- * Testing tool /usr/lib/systemd/systemd-activate is renamed to
+ * The testing tool /usr/lib/systemd/systemd-activate is renamed to
systemd-socket-activate and installed into /usr/bin. It is now fully
supported.
- * systemd-journald now uses separate threads to flush changes to
- disk when closing journal files.
+ * systemd-journald now uses separate threads to flush changes to disk
+ when closing journal files, thus reducing impact of slow disk I/O on
+ logging performance.
- * systemd-ask-password skips printing of the password to stdout
- with --no-output which can be useful in scripts.
+ * systemd-ask-password now optionally skips printing of the password to
+ stdout with --no-output which can be useful in scripts.
* Framebuffer devices (/dev/fb*) and 3D printers and scanners
(devices tagged with ID_MAKER_TOOL) are now tagged with
@@ -83,18 +89,99 @@ CHANGES WITH 230 in spe:
* systemd-bootchart has been split out to a separate repository:
https://github.com/systemd/systemd-bootchart
- * Compatibility libraries libsystemd-daemon.so, libsystemd-journal.so,
- libsystemd-id128.so, and libsystemd-login.so which have been
- deprecated since systemd-209 have been removed along along with the
- corresponding pkg-config files. All symbols provided by the those
- libraries are provided by libsystemd.so.
-
- * Capabilities= setting has been removed (it is ignored for backwards
- compatibility). AmbientCapabilities= and CapabilityBoundingSet=
- should be used instead.
+ * The compatibility libraries libsystemd-daemon.so,
+ libsystemd-journal.so, libsystemd-id128.so, and libsystemd-login.so
+ which have been deprecated since systemd-209 have been removed along
+ with the corresponding pkg-config files. All symbols provided by the
+ those libraries are provided by libsystemd.so.
+
+ * The Capabilities= unit file setting has been removed (it is ignored
+ for backwards compatibility). AmbientCapabilities= and
+ CapabilityBoundingSet= should be used instead.
+
+ * "systemctl show" gained a new --value switch, which allows print a
+ only the contents of a specific unit property, without also printing
+ the property's name. Similar support was added to "show*" verbs
+ of loginctl and machinectl that output "key=value" lists.
+
+ * A new command "systemctl revert" has been added that may be used to
+ revert to the vendor version of a unit file, in case local changes
+ have been made by adding drop-ins or overriding the unit file.
+
+ * "machinectl clean" gained a new verb to automatically remove all or
+ just hidden container images.
+
+ * systemd-bus-proxyd has been removed, as kdbus is unlikely to still be
+ merged into the kernel in its current form.
+
+ * systemd-networkd gained support for configuring proxy ARP support for
+ each interface, via the ProxyArp= setting in .network files. It also
+ gained support for configuring the multicast querier feature of
+ bridge devices, via the new MulticastQuerier= setting in .netdev
+ files. A new setting PreferredLifetime= has been added for addresses
+ configured in .network file to configure the lifetime intended for an
+ address.
+
+ * systemd-tmpfiles gained support for a new line type "e" for emptying
+ directories, if they exist, without creating them if they don't.
+
+ * journalctl learned a new output mode "-o short-unix" that outputs log
+ lines prefixed by their UNIX time (i.e. seconds since Jan 1st, 1970
+ UTC). It also gained support for a new --no-hostname setting to
+ suppress the hostname column in the family of "short" output modes.
+
+ * systemd-nspawn gained support for automatically patching the UID/GIDs
+ of the owners and the ACLs of all files and directories in a
+ container tree to match the UID/GID user namespacing range selected
+ for the container invocation. This mode is enabled via the new
+ --private-user-chown switch. It also gained support for automatically
+ choosing a free, previously unused UID/GID range when starting a
+ container, via the new --private-users=pick setting (which implies
+ --private-user-chown). Together, these options for the first time
+ make user namespacing for nspawn containers fully automatic and thus
+ deployable. The systemd-nspaw@.service template unit file has been
+ changed to use this functionality by default.
+
+ * The default start timeout may now be configured on the kernel command
+ line via systemd.default_timeout_start_sec=. It was already
+ configurable via the DefaultTimeoutStartSec= option in
+ /etc/systemd/system.conf.
+
+ * Socket units gained a new TriggerLimitIntervalSec= and
+ TriggerLimitBurst= setting to configure a limit on the activation
+ rate of the socket unit.
+
+ * The LimitNICE= setting now optionally takes normal UNIX nice values
+ in addition to the raw integer limit value. If the specified
+ parameter is prefixed with "+" or "-" and is in the range -20..19 the
+ value is understood as UNIX nice value. If not prefixed like this it
+ is understood as raw RLIMIT_NICE limit.
+
+ Contributions from: Alban Crequy, Alexander Kuleshov, Alex Crawford,
+ Andrew Eikum, Beniamino Galvani, Benjamin Robin, Benjamin ROBIN, Biao
+ Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Colin Guthrie, Daniel
+ J Walsh, Daniel Mack, Dan Nicholson, daurnimator, David Herrmann, David
+ R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko, Evgeny
+ Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger, Franck
+ Bui, frankheckenbach, Georgia Brikis, Harald Hoyer, Hendrik Brueckner,
+ Hristo Venev, Iago López Galeiras, Ian Kelling, Ismo Puustinen, Jakub
+ Wilk, Jaroslav Škarvada, Jeff Huang, Joel Holdsworth, kayrus, Klearchos
+ Chaloulos, Lennart Poettering, Lubomir Rintel, Lukas Nykryn, Lukáš
+ Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt, Michael Biebl,
+ michaelolbrich, Michał Bartoszkiewicz, Michal Koutný, Michal Sekletar,
+ Mike Frysinger, Mike Gilbert, Mingcong Bai, Ming Lin, mulkieran,
+ muzena, Nalin Dahyabhai, Naohiro Aota, Nathan McSween, Nicolas
+ Braud-Santoni, Patrik Flykt, Peter Hutterer, Petr Lautrbach, Petros
+ Angelatos, Piotr Drąg, Rabin Vincent, Robert Węcławski, Ronny
+ Chevalier, Samuel Tardieu, Stefan Schallenberg, Steven Siloti, Susant
+ Sahani, Sylvain Plantefève, Taylor Smock, tblume, Tejun Heo, Thomas
+ Blume, Thomas Haller, Thomas Hindoe Paaboel Andersen, Thomas
+ H. P. Andersen, Tobias Klauser, Tom Gundersen, Torstein Husebø, Umut
+ Tezduyar Lindskog, Vinay Kulkarni, Vito Caputo, Vittorio G (VittGam),
+ Vladimir Panteleev, Wieland Hoffmann, Wouter Verhelst, Yu Watanabe,
+ Zbigniew Jędrzejewski-Szmek
- * systemd-bus-proxyd has been removed, as kdbus will not be merged
- in current form.
+ — Berlin, 2016-05-XX
CHANGES WITH 229:
diff --git a/TODO b/TODO
index 57d731b46d..bf80f86e04 100644
--- a/TODO
+++ b/TODO
@@ -33,9 +33,11 @@ Janitorial Clean-ups:
Features:
-* journalctl: make sure -f ends when the container indicated by -M terminates
+* IAID field must move from [Link] to [DHCP] section in .network files
+
+* make sure the ratelimit object can deal with USEC_INFINITY as way to turn off things
-* make "machinectl clone" properly async, and add fallback for non-tmpfs
+* journalctl: make sure -f ends when the container indicated by -M terminates
* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
kernel doesn't support linkat() that replaces existing files, currently)
@@ -47,14 +49,9 @@ Features:
* make sure resolved can be restarted without losing pushed-in dns config
-* fix https://github.com/systemd/systemd/pull/2890, this shouldn't be exported
- like this.
-
* journald: sigbus API via a signal-handler safe function that people may call
from the SIGBUS handler
-* resolved: cefmz.x.incapdns.net fails to authenticate
-
* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
* move specifier expansion from service_spawn() into load-fragment.c
diff --git a/catalog/systemd.hr.catalog b/catalog/systemd.hr.catalog
index 4a6c5ac1fc..350988dd87 100644
--- a/catalog/systemd.hr.catalog
+++ b/catalog/systemd.hr.catalog
@@ -67,7 +67,7 @@ Zapamtite da samo poruke iz usluge u upitu su
odbačene, ostale poruke usluga nisu zahvaćene.
Ograničenja koja kontroliraju kada je poruka odbačena mogu se podesiti
-sa RateLimitInterval= i RateLimitBurst= u
+sa RateLimitIntervalSec= i RateLimitBurst= u
/etc/systemd/journald.conf. Pogledajte journald.conf(5) za više pojedinosti.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/configure.ac b/configure.ac
index 1d668623a4..d6320d2022 100644
--- a/configure.ac
+++ b/configure.ac
@@ -507,6 +507,14 @@ if test "x$enable_apparmor" != "xno"; then
fi
AM_CONDITIONAL(HAVE_APPARMOR, [test "$have_apparmor" = "yes"])
+have_adm_group=no
+AC_ARG_ENABLE(adm-group, AS_HELP_STRING([--disable-adm-group], [disable adm group]))
+AS_IF([test "x$enable_adm_group" != "xno"], [
+ AC_DEFINE(ENABLE_ADM_GROUP, 1, [Define if the ACL for adm group should be enabled])
+ have_adm_group=yes
+ M4_DEFINES="$M4_DEFINES -DENABLE_ADM_GROUP"
+])
+
have_wheel_group=no
AC_ARG_ENABLE(wheel-group, AS_HELP_STRING([--disable-wheel-group], [disable wheel group]))
AS_IF([test "x$enable_wheel_group" != "xno"], [
@@ -1657,6 +1665,7 @@ AC_MSG_RESULT([
Zsh completions dir: ${with_zshcompletiondir}
Extra start script: ${RC_LOCAL_SCRIPT_PATH_START}
Extra stop script: ${RC_LOCAL_SCRIPT_PATH_STOP}
+ Adm group: ${have_adm_group}
Wheel group: ${have_wheel_group}
Debug shell: ${SUSHELL} @ ${DEBUGTTY}
TTY GID: ${TTY_GID}
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
index 6ba35414be..fe92277a1f 100644
--- a/man/logind.conf.xml
+++ b/man/logind.conf.xml
@@ -297,6 +297,22 @@
</varlistentry>
<varlistentry>
+ <term><varname>InhibitorsMax=</varname></term>
+
+ <listitem><para>Controls the maximum number of concurrent inhibitors to permit. Defaults to 8192
+ (8K).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>SessionsMax=</varname></term>
+
+ <listitem><para>Controls the maximum number of concurrent user sessions to manage. Defaults to 8192
+ (8K). Depending on how the <filename>pam_systemd.so</filename> module is included in the PAM stack
+ configuration, further login sessions will either be refused, or permitted but not tracked by
+ <filename>systemd-logind</filename>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>UserTasksMax=</varname></term>
<listitem><para>Sets the maximum number of OS tasks each user
diff --git a/man/machinectl.xml b/man/machinectl.xml
index 43a3b98840..4b7f9a0391 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -589,13 +589,11 @@
<varlistentry>
<term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
- <listitem><para>Clones a container or VM image. The
- arguments specify the name of the image to clone and the name
- of the newly cloned image. Note that plain directory container
- images are cloned into subvolume images with this command.
- Note that cloning a container or VM image is optimized for
- btrfs file systems, and might not be efficient on others, due
- to file system limitations.</para>
+ <listitem><para>Clones a container or VM image. The arguments specify the name of the image to clone and the
+ name of the newly cloned image. Note that plain directory container images are cloned into btrfs subvolume
+ images with this command, if the underlying file system supports this. Note that cloning a container or VM
+ image is optimized for btrfs file systems, and might not be efficient on others, due to file system
+ limitations.</para>
<para>Note that this command leaves host name, machine ID and
all other settings that could identify the instance
diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml
index 5166e05cbc..4bfc4f773a 100644
--- a/man/networkd.conf.xml
+++ b/man/networkd.conf.xml
@@ -58,14 +58,14 @@
<title>Description</title>
<para>These configuration files control global network parameters.
- For e.g. DHCP Unique Identifier (DUID).</para>
+ Currently the DHCP Unique Identifier (DUID).</para>
</refsect1>
<xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
- <title>[DUID] Section Options</title>
+ <title>[DHCP] Section Options</title>
<para>This section configures the DHCP Unique Identifier (DUID) value used by DHCP
protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface
@@ -73,28 +73,71 @@
address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring
a dynamic IPv4 address if <option>ClientIdentifier=duid</option>. IAID and DUID allows
a DHCP server to uniquely identify the machine and the interface requesting a DHCP IP.
- To configure IAID and ClientIdentifier, see <citerefentry><refentrytitle>systemd.network
- </refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ To configure IAID and ClientIdentifier, see
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
- <para>The DUID value specified here overrides the DUID that systemd-networkd
- generates using the machine-id from the <filename>/etc/machine-id</filename> file.
- To configure DUID per-network, see <citerefentry><refentrytitle>systemd.network
- </refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
-
- <para>The configured DHCP DUID should conform to the specification in
- <ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
- <ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>. To configure IAID, see
- <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum>
- </citerefentry>.</para>
-
- <para>The following options are available in <literal>[DUID]</literal> section:</para>
+ <para>The following options are understood:</para>
<variablelist class='network-directives'>
+ <varlistentry>
+ <term><varname>DUIDType=</varname></term>
+ <listitem><para>Specifies how the DUID should be generated. See
+ <ulink url="https://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>
+ for a description of all the options.</para>
+
+ <para>The following values are understood:
+ <variablelist>
+ <varlistentry>
+ <term><option>vendor</option> </term>
+ <listitem><para>If <literal>DUIDType=vendor</literal>, then the DUID value will be generated using
+ <literal>43793</literal> as the vendor identifier (systemd) and hashed contents of
+ <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ This is the default if <varname>DUIDType=</varname> is not specified.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>link-layer-time</option> </term>
+ <term><option>link-layer</option> </term>
+ <term><option>uuid</option> </term>
+ <listitem><para>Those values are parsed and can be used to set the DUID type
+ field, but DUID contents must be provided using <varname>DUIDRawData=</varname>.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>In all cases, <varname>DUIDRawData=</varname> can be used to override the
+ actual DUID value that is used.</para></listitem>
+ </varlistentry>
<varlistentry>
- <term><varname>RawData=</varname></term>
- <listitem><para>Specifies the DUID bytes as a single newline-terminated, hexadecimal
- string, with each byte separated by a ':'.</para></listitem>
+ <term><varname>DUIDRawData=</varname></term>
+ <listitem><para>Specifies the DHCP DUID value as a single newline-terminated, hexadecimal string, with each
+ byte separated by <literal>:</literal>. The DUID that is sent is composed of the DUID type specified by
+ <varname>DUIDType=</varname> and the value configured here.</para>
+
+ <para>The DUID value specified here overrides the DUID that systemd-networkd generates using the machine-id
+ from the <filename>/etc/machine-id</filename> file. To configure DUID per-network, see
+ <citerefentry><refentrytitle>systemd.network </refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ The configured DHCP DUID should conform to the specification in
+ <ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
+ <ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>. To configure IAID, see
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>.</para>
+
+ <example>
+ <title>A <option>DUIDType=vendor</option> with a custom value</title>
+
+ <programlisting>DUIDType=vendor
+DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</programlisting>
+
+ <para>This specifies a 14 byte DUID, with the type DUID-EN (<literal>00:02</literal>), enterprise number
+ 43793 (<literal>00:00:ab:11</literal>), and identifier value <literal>f9:2a:c2:77:29:f9:5c:00</literal>.
+ </para>
+ </example>
+ </listitem>
</varlistentry>
</variablelist>
</refsect1>
diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml
index 93bae2a6dc..a43dc981bd 100644
--- a/man/systemd.automount.xml
+++ b/man/systemd.automount.xml
@@ -66,14 +66,13 @@
[Install] sections. The automount specific configuration options
are configured in the [Automount] section.</para>
- <para>Automount units must be named after the automount
- directories they control. Example: the automount point
- <filename noindex='true'>/home/lennart</filename> must be
- configured in a unit file
- <filename>home-lennart.automount</filename>. For details about the
- escaping logic used to convert a file system path to a unit name
- see
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ <para>Automount units must be named after the automount directories they control. Example: the automount point
+ <filename noindex='true'>/home/lennart</filename> must be configured in a unit file
+ <filename>home-lennart.automount</filename>. For details about the escaping logic used to convert a file system
+ path to a unit name see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that
+ automount units cannot be templated, nor is it possible to add multiple names to an automount unit by creating
+ additional symlinks to its unit file.</para>
<para>For each automount unit file a matching mount unit file (see
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index f116782b40..bf56a49e58 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -82,14 +82,12 @@
will refuse options that are not listed in
<filename>/etc/fstab</filename> if it is not run as UID 0.</para>
- <para>Mount units must be named after the mount point directories
- they control. Example: the mount point
- <filename noindex='true'>/home/lennart</filename> must be
- configured in a unit file <filename>home-lennart.mount</filename>.
- For details about the escaping logic used to convert a file system
- path to a unit name, see
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
- Note that mount units cannot be templated.</para>
+ <para>Mount units must be named after the mount point directories they control. Example: the mount point <filename
+ noindex='true'>/home/lennart</filename> must be configured in a unit file <filename>home-lennart.mount</filename>.
+ For details about the escaping logic used to convert a file system path to a unit name, see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that mount
+ units cannot be templated, nor is possible to add multiple names to a mount unit by creating additional symlinks to
+ it.</para>
<para>Optionally, a mount unit may be accompanied by an automount
unit, to allow on-demand or parallelized mounting. See
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 2a20748376..3ee80a64a0 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -652,6 +652,18 @@
<para>An address label.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>PreferredLifetime=</varname></term>
+ <listitem>
+ <para>Allows the default "preferred lifetime" of the address to be overridden.
+ Only three settings are accepted: <literal>forever</literal> or <literal>infinity</literal>
+ which is the default and means that the address never expires, and <literal>0</literal> which means
+ that the address is considered immediately "expired" and will not be used,
+ unless explicitly requested. A setting of PreferredLifetime=0 is useful for
+ addresses which are added to be used only by a specific application,
+ which is then configured to use them explicitly.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -706,6 +718,14 @@
<citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>Table=<replaceable>num</replaceable></varname></term>
+ <listitem>
+ <para>The table identifier for the route (a number between 1 and 4294967295, or 0 to unset).
+ The table can be retrieved using <command>ip route show table <replaceable>num</replaceable></command>.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -812,6 +832,7 @@
false.</para>
</listitem>
</varlistentry>
+
<varlistentry>
<term><varname>ClientIdentifier=</varname></term>
<listitem>
@@ -819,6 +840,7 @@
or <literal>duid</literal> (the default, see below) to use a RFC4361-compliant Client ID.</para>
</listitem>
</varlistentry>
+
<varlistentry>
<term><varname>VendorClassIdentifier=</varname></term>
<listitem>
@@ -826,25 +848,25 @@
type and configuration.</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term><varname>DUIDRawData=</varname></term>
- <listitem><para>Specifies the DHCP DUID bytes as a single newline-terminated, hexadecimal string, with each
- byte separated by a ':'. A DHCPv6 client sends the DHCP Unique Identifier (DUID) and the interface Identity
- Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 address. Similar, DHCPv4 clients
- send the IAID and DUID to the DHCP server when acquiring a dynamic IPv4 address if
- <option>ClientIdentifier=duid</option>. IAID and DUID allows a DHCP server to uniquely identify the machine
- and the interface requesting a DHCP IP address.</para>
- <para>The DUID value specified here takes precedence over the DUID that systemd-networkd generates
- using the machine-id from the <filename>/etc/machine-id</filename> file, as well as the
- global DUID that may be specified in <citerefentry><refentrytitle>networkd.conf
- </refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ <varlistentry>
+ <term><varname>DUIDType=</varname></term>
+ <listitem>
+ <para>Override the global <varname>DUIDType</varname> setting for this network. See
+ <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for a description of possible values.</para>
+ </listitem>
+ </varlistentry>
- <para>The configured DHCP DUID should conform to the specification in
- <ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
- <ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>.</para>
+ <varlistentry>
+ <term><varname>DUIDRawData=</varname></term>
+ <listitem>
+ <para>Override the global <varname>DUIDRawData</varname> setting for this network. See
+ <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for a description of possible values.</para>
</listitem>
</varlistentry>
+
<varlistentry>
<term><varname>RequestBroadcast=</varname></term>
<listitem>
@@ -856,6 +878,7 @@
networks where broadcasts are filtered out.</para>
</listitem>
</varlistentry>
+
<varlistentry>
<term><varname>RouteMetric=</varname></term>
<listitem>
diff --git a/man/systemd.slice.xml b/man/systemd.slice.xml
index 16247628af..eee98d99ee 100644
--- a/man/systemd.slice.xml
+++ b/man/systemd.slice.xml
@@ -71,6 +71,9 @@
the root slice <filename>-.slice</filename>.
</para>
+ <para>Note that slice units cannot be templated, nor is possible to add multiple names to a slice unit by creating
+ additional symlinks to it.</para>
+
<para>By default, service and scope units are placed in
<filename>system.slice</filename>, virtual machines and containers
registered with
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index dc3fee5dfb..5bf54d8ef3 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -809,18 +809,19 @@
<varlistentry>
<term><varname>TriggerLimitIntervalSec=</varname></term>
- <term><varname>TriggerLimitIntervalBurst=</varname></term>
+ <term><varname>TriggerLimitBurst=</varname></term>
<listitem><para>Configures a limit on how often this socket unit my be activated within a specific time
interval. The <varname>TriggerLimitIntervalSec=</varname> may be used to configure the length of the time
interval in the usual time units <literal>us</literal>, <literal>ms</literal>, <literal>s</literal>,
- <literal>min</literal>, <literal>h</literal>, … and defaults to 5s (See
+ <literal>min</literal>, <literal>h</literal>, … and defaults to 2s (See
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details on
- the various time units available). The <varname>TriggerLimitBurst=</varname> setting takes an integer value and
- specifies the numer of permitted activations per time interval, and defaults to 2500 (thus by default
- permitting 2500 activations per 5s). Set either to 0 to disable any form of trigger rate limiting. If the limit
- is hit, the socket unit is placed into a failure mode, and will not be connectible anymore until
- restarted. Note that this limit is enforced before the service activation is enqueued.</para></listitem>
+ the various time units understood). The <varname>TriggerLimitBurst=</varname> setting takes a positive integer
+ value and specifies the number of permitted activations per time interval, and defaults to 200 for
+ <varname>Accept=yes</varname> sockets (thus by default permitting 200 activations per 2s), and 20 otherwise (20
+ activations per 2s). Set either to 0 to disable any form of trigger rate limiting. If the limit is hit, the
+ socket unit is placed into a failure mode, and will not be connectible anymore until restarted. Note that this
+ limit is enforced before the service activation is enqueued.</para></listitem>
</varlistentry>
</variablelist>
diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml
index 6fc4c7bf13..cf4e1ba839 100644
--- a/man/systemd.swap.xml
+++ b/man/systemd.swap.xml
@@ -78,13 +78,12 @@
which configure resource control settings for these processes of the
unit.</para>
- <para>Swap units must be named after the devices
- or files they control. Example: the swap device
- <filename noindex='true'>/dev/sda5</filename> must be configured in a
- unit file <filename>dev-sda5.swap</filename>. For details about
- the escaping logic used to convert a file system path to a unit
- name, see
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ <para>Swap units must be named after the devices or files they control. Example: the swap device <filename
+ noindex='true'>/dev/sda5</filename> must be configured in a unit file <filename>dev-sda5.swap</filename>. For
+ details about the escaping logic used to convert a file system path to a unit name, see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that swap
+ units cannot be templated, nor is possible to add multiple names to a swap unit by creating additional symlinks to
+ it.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index f4b13a7a77..90a1ec6b9c 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -770,7 +770,9 @@
<command>systemctl reset-failed</command> will cause the restart rate counter for a service to be flushed,
which is useful if the administrator wants to manually start a unit and the start limit interferes with
that. Note that this rate-limiting is enforced after any unit condition checks are executed, and hence unit
- activations with failing conditions are not counted by this rate limiting.</para></listitem>
+ activations with failing conditions are not counted by this rate limiting. Slice, target, device and scope
+ units do not enforce this setting, as they are unit types whose activation may either never fail, or may
+ succeed only a single time.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1103,13 +1105,12 @@
<varlistentry>
<term><varname>Alias=</varname></term>
- <listitem><para>A space-separated list of additional names
- this unit shall be installed under. The names listed here must
- have the same suffix (i.e. type) as the unit file name. This
- option may be specified more than once, in which case all
- listed names are used. At installation time,
- <command>systemctl enable</command> will create symlinks from
- these names to the unit filename.</para></listitem>
+ <listitem><para>A space-separated list of additional names this unit shall be installed under. The names listed
+ here must have the same suffix (i.e. type) as the unit file name. This option may be specified more than once,
+ in which case all listed names are used. At installation time, <command>systemctl enable</command> will create
+ symlinks from these names to the unit filename. Note that not all unit types support such alias names, and this
+ setting is not supported for them. Specifically, mount, slice, swap, and automount units do not support
+ aliasing.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/po/it.po b/po/it.po
index a8547b9395..24504da42b 100644
--- a/po/it.po
+++ b/po/it.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-11-22 16:37+0100\n"
-"PO-Revision-Date: 2015-11-22 16:54+0100\n"
+"POT-Creation-Date: 2016-05-07 04:45+0200\n"
+"PO-Revision-Date: 2016-05-07 04:55+0200\n"
"Last-Translator: Daniele Medri <dmedri@gmail.com>\n"
"Language-Team: Italian\n"
"Language: it\n"
@@ -16,11 +16,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.8.5\n"
+"X-Generator: Poedit 1.8.7.1\n"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
msgid "Send passphrase back to system"
-msgstr "Inviare la frase segreta (passphrase) al sistema"
+msgstr "Invia la frase segreta (passphrase) al sistema"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
msgid ""
@@ -63,7 +63,7 @@ msgstr ""
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
msgid "Reload the systemd state"
-msgstr "Riavviare lo stato di systemd"
+msgstr "Riavvia lo stato di systemd"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
msgid "Authentication is required to reload the systemd state."
@@ -251,48 +251,58 @@ msgstr ""
"gestione di sistema alla apertura/chiusura del portatile."
#: ../src/login/org.freedesktop.login1.policy.in.h:19
-msgid "Allow non-logged-in users to run programs"
+msgid "Allow non-logged-in user to run programs"
msgstr "Consenti agli utenti non connessi di eseguire programmi"
#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Explicit request is required to run programs as a non-logged-in user."
+msgstr ""
+"E' necessaria un'esplicita richiesta per eseguire programmi come utenti non "
+"connessi."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
+msgid "Allow non-logged-in users to run programs"
+msgstr "Consenti agli utenti non connessi di eseguire programmi"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
msgid "Authentication is required to run programs as a non-logged-in user."
msgstr ""
"Autenticazione richiesta per consentire agli utenti non connessi di eseguire "
"programmi."
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
msgid "Allow attaching devices to seats"
msgstr "Consenti di collegare dispositivi alle postazioni"
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
msgid "Authentication is required for attaching a device to a seat."
msgstr ""
"Autenticazione richiesta per collegare un dispositivo ad una postazione."
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
msgid "Flush device to seat attachments"
msgstr "Scollega i dispositivi dalla postazione"
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
msgid ""
"Authentication is required for resetting how devices are attached to seats."
msgstr ""
"Autenticazione richiesta per ripristinare come i dispositivi sono collegati "
"alle postazioni."
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
msgid "Power off the system"
-msgstr "Spegnere il sistema"
+msgstr "Spegni il sistema (power off)"
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
msgid "Authentication is required for powering off the system."
msgstr "Autenticazione richiesta per spegnere il sistema."
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
msgid "Power off the system while other users are logged in"
-msgstr "Spegnere il sistema mentre altri utenti sono connessi"
+msgstr "Spegni il sistema (power off) mentre altri utenti sono connessi"
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
msgid ""
"Authentication is required for powering off the system while other users are "
"logged in."
@@ -300,11 +310,13 @@ msgstr ""
"Autenticazione richiesta per spegnere il sistema mentre altri utenti sono "
"connessi."
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
msgid "Power off the system while an application asked to inhibit it"
-msgstr "Spegnere il sistema mentre un'applicazione chiede di inibirne l'azione"
+msgstr ""
+"Spegni il sistema (power off) mentre un'applicazione chiede di inibirne "
+"l'azione"
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
msgid ""
"Authentication is required for powering off the system while an application "
"asked to inhibit it."
@@ -312,19 +324,19 @@ msgstr ""
"Autenticazione richiesta per spegnere il sistema mentre un'applicazione "
"chiede di inibirne l'azione."
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
msgid "Reboot the system"
-msgstr "Riavviare il sistema"
+msgstr "Riavvia il sistema (reboot)"
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
msgid "Authentication is required for rebooting the system."
msgstr "Autenticazione richiesta per riavviare il sistema."
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
msgid "Reboot the system while other users are logged in"
-msgstr "Riavviare il sistema mentre altri utenti sono connessi"
+msgstr "Riavvia il sistema (reboot) mentre altri utenti sono connessi"
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
msgid ""
"Authentication is required for rebooting the system while other users are "
"logged in."
@@ -332,12 +344,13 @@ msgstr ""
"Autenticazione richiesta per riavviare il sistema mentre altri utenti sono "
"connessi."
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
msgid "Reboot the system while an application asked to inhibit it"
msgstr ""
-"Riavviare il sistema mentre un'applicazione chiede di inibirne l'azione"
+"Riavvia il sistema (reboot) mentre un'applicazione chiede di inibirne "
+"l'azione"
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
msgid ""
"Authentication is required for rebooting the system while an application "
"asked to inhibit it."
@@ -345,19 +358,19 @@ msgstr ""
"Autenticazione richiesta per riavviare il sistema mentre un'applicazione "
"chiede di inibirne l'azione."
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
msgid "Suspend the system"
-msgstr "Sospendere il sistema"
+msgstr "Sospendi il sistema (suspend)"
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
msgid "Authentication is required for suspending the system."
msgstr "Autenticazione richiesta per sospendere il sistema."
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
msgid "Suspend the system while other users are logged in"
-msgstr "Sospendere il sistema mentre altri utenti sono connessi"
+msgstr "Sospendi il sistema (suspend) mentre altri utenti sono connessi"
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
msgid ""
"Authentication is required for suspending the system while other users are "
"logged in."
@@ -365,12 +378,13 @@ msgstr ""
"Autenticazione richiesta per sospendere il sistema mentre altri utenti sono "
"connessi."
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
msgid "Suspend the system while an application asked to inhibit it"
msgstr ""
-"Sospendere il sistema mentre un'applicazione chiede di inibirne l'azione"
+"Sospendi il sistema (suspend) mentre un'applicazione chiede di inibirne "
+"l'azione"
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
msgid ""
"Authentication is required for suspending the system while an application "
"asked to inhibit it."
@@ -378,19 +392,19 @@ msgstr ""
"Autenticazione richiesta per sospendere il sistema mentre un'applicazione "
"chiede di inibirne l'azione."
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
msgid "Hibernate the system"
-msgstr "Ibernare il sistema"
+msgstr "Iberna il sistema (hibernate)"
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
msgid "Authentication is required for hibernating the system."
msgstr "Autenticazione richiesta per ibernare il sistema."
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
msgid "Hibernate the system while other users are logged in"
-msgstr "Ibernare il sistema mentre altri utenti sono connessi"
+msgstr "Iberna il sistema (hibernate) mentre altri utenti sono connessi"
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
msgid ""
"Authentication is required for hibernating the system while other users are "
"logged in."
@@ -398,11 +412,13 @@ msgstr ""
"Autenticazione richiesta per ibernare il sistema mentre altri utenti sono "
"connessi."
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
msgid "Hibernate the system while an application asked to inhibit it"
-msgstr "Ibernare il sistema mentre un'applicazione chiede di inibirne l'azione"
+msgstr ""
+"Iberna il sistema (hibernate) mentre un'applicazione chiede di inibirne "
+"l'azione"
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
msgid ""
"Authentication is required for hibernating the system while an application "
"asked to inhibit it."
@@ -410,32 +426,32 @@ msgstr ""
"Autenticazione richiesta per ibernare il sistema mentre un'applicazione "
"chiede di inibirne l'azione."
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
msgid "Manage active sessions, users and seats"
msgstr "Gestione delle sessioni attive, utenti e postazioni"
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
msgid ""
"Authentication is required for managing active sessions, users and seats."
msgstr ""
"Autenticazione richiesta per gestire le sessioni attive, gli utenti e le "
"postazioni."
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
msgid "Lock or unlock active sessions"
msgstr "Blocca/sblocca sessioni attive"
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
msgid "Authentication is required to lock or unlock active sessions."
msgstr "Autenticazione richiesta per bloccare o sbloccare le sessioni attive."
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
msgid "Allow indication to the firmware to boot to setup interface"
msgstr ""
"Permette indicazioni per il firmware per avviare l'interfaccia di "
"configurazione"
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
msgid ""
"Authentication is required to indicate to the firmware to boot to setup "
"interface."
@@ -443,11 +459,11 @@ msgstr ""
"Autenticazione richiesta per indicare al firmware di avviare l'interfaccia "
"di configurazione."
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: ../src/login/org.freedesktop.login1.policy.in.h:57
msgid "Set a wall message"
msgstr "Configura un messaggio per gli utenti"
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: ../src/login/org.freedesktop.login1.policy.in.h:58
msgid "Authentication is required to set a wall message"
msgstr "Autenticazione richiesta per configurare un messaggio per gli utenti"
@@ -565,31 +581,31 @@ msgstr ""
"Autenticazione richiesta per verificare se la sincronizzazione dell'orario "
"in rete possa essere attivata."
-#: ../src/core/dbus-unit.c:428
+#: ../src/core/dbus-unit.c:450
msgid "Authentication is required to start '$(unit)'."
msgstr "Autenticazione richiesta per avviare '$(unit)'."
-#: ../src/core/dbus-unit.c:429
+#: ../src/core/dbus-unit.c:451
msgid "Authentication is required to stop '$(unit)'."
msgstr "Autenticazione richiesta per fermare '$(unit)'."
-#: ../src/core/dbus-unit.c:430
+#: ../src/core/dbus-unit.c:452
msgid "Authentication is required to reload '$(unit)'."
msgstr "Autenticazione richiesta per ricaricare '$(unit)'."
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+#: ../src/core/dbus-unit.c:453 ../src/core/dbus-unit.c:454
msgid "Authentication is required to restart '$(unit)'."
msgstr "Autenticazione richiesta per riavviare '$(unit)'."
-#: ../src/core/dbus-unit.c:535
+#: ../src/core/dbus-unit.c:560
msgid "Authentication is required to kill '$(unit)'."
msgstr "Autenticazione richiesta per terminare '$(unit)'."
-#: ../src/core/dbus-unit.c:565
+#: ../src/core/dbus-unit.c:590
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr ""
"Autenticazione richiesta per riconfigurare lo stato \"fallito\" di '$(unit)'."
-#: ../src/core/dbus-unit.c:597
+#: ../src/core/dbus-unit.c:622
msgid "Authentication is required to set properties on '$(unit)'."
msgstr "Autenticazione richiesta per configurare le proprietà di '$(unit)'."
diff --git a/src/basic/architecture.c b/src/basic/architecture.c
index a9ecfc1cd6..8e2c2b02d2 100644
--- a/src/basic/architecture.c
+++ b/src/basic/architecture.c
@@ -121,6 +121,8 @@ int uname_architecture(void) {
{ "tilegx", ARCHITECTURE_TILEGX },
#elif defined(__cris__)
{ "crisv32", ARCHITECTURE_CRIS },
+#elif defined(__nios2__)
+ { "nios2", ARCHITECTURE_NIOS2 },
#else
#error "Please register your architecture here!"
#endif
@@ -171,6 +173,7 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = {
[ARCHITECTURE_M68K] = "m68k",
[ARCHITECTURE_TILEGX] = "tilegx",
[ARCHITECTURE_CRIS] = "cris",
+ [ARCHITECTURE_NIOS2] = "nios2",
};
DEFINE_STRING_TABLE_LOOKUP(architecture, int);
diff --git a/src/basic/architecture.h b/src/basic/architecture.h
index c22cbc8279..91ec108e04 100644
--- a/src/basic/architecture.h
+++ b/src/basic/architecture.h
@@ -57,6 +57,7 @@ enum {
ARCHITECTURE_M68K,
ARCHITECTURE_TILEGX,
ARCHITECTURE_CRIS,
+ ARCHITECTURE_NIOS2,
_ARCHITECTURE_MAX,
_ARCHITECTURE_INVALID = -1
};
@@ -187,6 +188,9 @@ int uname_architecture(void);
#elif defined(__cris__)
# define native_architecture() ARCHITECTURE_CRIS
# error "Missing LIB_ARCH_TUPLE for CRIS"
+#elif defined(__nios2__)
+# define native_architecture() ARCHITECTURE_NIOS2
+# define LIB_ARCH_TUPLE "nios2-linux-gnu"
#else
# error "Please register your architecture here!"
#endif
diff --git a/src/basic/copy.c b/src/basic/copy.c
index 3001234a01..c3586728d0 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -305,6 +305,8 @@ static int fd_copy_directory(
fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
else
fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
+ if (fdf < 0)
+ return -errno;
d = fdopendir(fdf);
if (!d)
@@ -325,22 +327,6 @@ static int fd_copy_directory(
r = 0;
- if (created) {
- struct timespec ut[2] = {
- st->st_atim,
- st->st_mtim
- };
-
- if (fchown(fdt, st->st_uid, st->st_gid) < 0)
- r = -errno;
-
- if (fchmod(fdt, st->st_mode & 07777) < 0)
- r = -errno;
-
- (void) futimens(fdt, ut);
- (void) copy_xattr(dirfd(d), fdt);
- }
-
FOREACH_DIRENT_ALL(de, d, return -errno) {
struct stat buf;
int q;
@@ -376,6 +362,22 @@ static int fd_copy_directory(
r = q;
}
+ if (created) {
+ struct timespec ut[2] = {
+ st->st_atim,
+ st->st_mtim
+ };
+
+ if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+ r = -errno;
+
+ if (fchmod(fdt, st->st_mode & 07777) < 0)
+ r = -errno;
+
+ (void) copy_xattr(dirfd(d), fdt);
+ (void) futimens(fdt, ut);
+ }
+
return r;
}
@@ -407,7 +409,6 @@ int copy_tree(const char *from, const char *to, bool merge) {
}
int copy_directory_fd(int dirfd, const char *to, bool merge) {
-
struct stat st;
assert(dirfd >= 0);
@@ -422,6 +423,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
}
+int copy_directory(const char *from, const char *to, bool merge) {
+ struct stat st;
+
+ assert(from);
+ assert(to);
+
+ if (lstat(from, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return -ENOTDIR;
+
+ return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+}
+
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
_cleanup_close_ int fdf = -1;
int r;
diff --git a/src/basic/copy.h b/src/basic/copy.h
index 3e5eb52506..b5d08ebafe 100644
--- a/src/basic/copy.h
+++ b/src/basic/copy.h
@@ -30,6 +30,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
+int copy_directory(const char *from, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
int copy_times(int fdf, int fdt);
int copy_xattr(int fdf, int fdt);
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 2a9b6e46ad..29f5374222 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1337,7 +1337,7 @@ int link_tmpfile(int fd, const char *path, const char *target) {
* created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
* on the directory, and renameat2() is used instead.
*
- * Note that in both cases we will not replace existing files. This is because linkat() dos not support this
+ * Note that in both cases we will not replace existing files. This is because linkat() does not support this
* operation currently (renameat2() does), and there is no nice way to emulate this. */
if (path) {
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 85b8d812b3..49a0479592 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -1773,20 +1773,18 @@ int set_consume(Set *s, void *value) {
int set_put_strdup(Set *s, const char *p) {
char *c;
- int r;
assert(s);
assert(p);
+ if (set_contains(s, (char*) p))
+ return 0;
+
c = strdup(p);
if (!c)
return -ENOMEM;
- r = set_consume(s, c);
- if (r == -EEXIST)
- return 0;
-
- return r;
+ return set_consume(s, c);
}
int set_put_strdupv(Set *s, char **l) {
diff --git a/src/basic/log.c b/src/basic/log.c
index d89e6f7274..3ea643b6e6 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -165,7 +165,7 @@ static int log_open_syslog(void) {
goto fail;
}
- if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
safe_close(syslog_fd);
/* Some legacy syslog systems still use stream
@@ -177,7 +177,7 @@ static int log_open_syslog(void) {
goto fail;
}
- if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
@@ -215,7 +215,7 @@ static int log_open_journal(void) {
goto fail;
}
- if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index f2cea01979..4a7367cc92 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -528,14 +528,20 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
return -EPROTO;
}
-void sigkill_wait(pid_t *pid) {
+void sigkill_wait(pid_t pid) {
+ assert(pid > 1);
+
+ if (kill(pid, SIGKILL) > 0)
+ (void) wait_for_terminate(pid, NULL);
+}
+
+void sigkill_waitp(pid_t *pid) {
if (!pid)
return;
if (*pid <= 1)
return;
- if (kill(*pid, SIGKILL) > 0)
- (void) wait_for_terminate(*pid, NULL);
+ sigkill_wait(*pid);
}
int kill_and_sigcont(pid_t pid, int sig) {
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index ffd4bcb0ff..9f75088796 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -58,8 +58,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid);
int wait_for_terminate(pid_t pid, siginfo_t *status);
int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
-void sigkill_wait(pid_t *pid);
-#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
+void sigkill_wait(pid_t pid);
+void sigkill_waitp(pid_t *pid);
int kill_and_sigcont(pid_t pid, int sig);
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index d17a2f35f8..daa4b24a37 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -137,3 +137,14 @@ ssize_t next_datagram_size_fd(int fd);
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
+
+/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
+#define SOCKADDR_UN_LEN(sa) \
+ ({ \
+ const struct sockaddr_un *_sa = &(sa); \
+ assert(_sa->sun_family == AF_UNIX); \
+ offsetof(struct sockaddr_un, sun_path) + \
+ (_sa->sun_path[0] == 0 ? \
+ 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
+ strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \
+ })
diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c
index 797f00cf71..4bef87d3c2 100644
--- a/src/basic/strbuf.c
+++ b/src/basic/strbuf.c
@@ -156,12 +156,13 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
return off;
}
+ c = s[len - 1 - depth];
+
/* bsearch is not allowed on a NULL sequence */
if (node->children_count == 0)
break;
/* lookup child node */
- c = s[len - 1 - depth];
search.c = c;
child = bsearch(&search, node->children, node->children_count,
sizeof(struct strbuf_child_entry),
diff --git a/src/basic/virt.c b/src/basic/virt.c
index e6c5a095a0..dace1f4328 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -280,7 +280,7 @@ static int detect_vm_uml(void) {
return VIRTUALIZATION_UML;
}
- log_debug("No virtualization found in /proc/cpuinfo (%s)", cpuinfo_contents);
+ log_debug("No virtualization found in /proc/cpuinfo.");
return VIRTUALIZATION_NONE;
}
diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c
index aadfba0707..d7c722ac3d 100644
--- a/src/cgroups-agent/cgroups-agent.c
+++ b/src/cgroups-agent/cgroups-agent.c
@@ -18,15 +18,22 @@
***/
#include <stdlib.h>
+#include <sys/socket.h>
-#include "sd-bus.h"
-
-#include "bus-util.h"
+#include "fd-util.h"
#include "log.h"
+#include "socket-util.h"
int main(int argc, char *argv[]) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- int r;
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/cgroups-agent",
+ };
+
+ _cleanup_close_ int fd = -1;
+ ssize_t n;
+ size_t l;
if (argc != 2) {
log_error("Incorrect number of arguments.");
@@ -37,27 +44,22 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- /* We send this event to the private D-Bus socket and then the
- * system instance will forward this to the system bus. We do
- * this to avoid an activation loop when we start dbus when we
- * are called when the dbus service is shut down. */
-
- r = bus_connect_system_systemd(&bus);
- if (r < 0) {
- /* If we couldn't connect we assume this was triggered
- * while systemd got restarted/transitioned from
- * initrd to the system, so let's ignore this */
- log_debug_errno(r, "Failed to get D-Bus connection: %m");
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ log_debug_errno(errno, "Failed to allocate socket: %m");
+ return EXIT_FAILURE;
+ }
+
+ l = strlen(argv[1]);
+
+ n = sendto(fd, argv[1], l, 0, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (n < 0) {
+ log_debug_errno(errno, "Failed to send cgroups agent message: %m");
return EXIT_FAILURE;
}
- r = sd_bus_emit_signal(bus,
- "/org/freedesktop/systemd1/agent",
- "org.freedesktop.systemd1.Agent",
- "Released",
- "s", argv[1]);
- if (r < 0) {
- log_debug_errno(r, "Failed to send signal message on private connection: %m");
+ if ((size_t) n != l) {
+ log_debug("Datagram size mismatch");
return EXIT_FAILURE;
}
diff --git a/src/core/automount.c b/src/core/automount.c
index 7c55d7bc49..f06d837e30 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -75,6 +75,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
static int open_dev_autofs(Manager *m);
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
+static int automount_start_expire(Automount *a);
+static void automount_stop_expire(Automount *a);
+static int automount_send_ready(Automount *a, Set *tokens, int status);
static void automount_init(Unit *u) {
Automount *a = AUTOMOUNT(u);
@@ -87,8 +90,6 @@ static void automount_init(Unit *u) {
UNIT(a)->ignore_on_isolate = true;
}
-static int automount_send_ready(Automount *a, Set *tokens, int status);
-
static void unmount_autofs(Automount *a) {
int r;
@@ -235,6 +236,9 @@ static void automount_set_state(Automount *a, AutomountState state) {
old_state = a->state;
a->state = state;
+ if (state != AUTOMOUNT_RUNNING)
+ automount_stop_expire(a);
+
if (state != AUTOMOUNT_WAITING &&
state != AUTOMOUNT_RUNNING)
unmount_autofs(a);
@@ -408,7 +412,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in
init_autofs_dev_ioctl(&param);
param.ioctlfd = ioctl_fd;
- if (status) {
+ if (status != 0) {
param.fail.token = token;
param.fail.status = status;
} else
@@ -435,7 +439,7 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
if (ioctl_fd < 0)
return ioctl_fd;
- if (status)
+ if (status != 0)
log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
else
log_unit_debug(UNIT(a), "Sending success.");
@@ -462,59 +466,54 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
return r;
}
-static int automount_start_expire(Automount *a);
-
-int automount_update_mount(Automount *a, MountState old_state, MountState state) {
+static void automount_trigger_notify(Unit *u, Unit *other) {
+ Automount *a = AUTOMOUNT(u);
int r;
assert(a);
+ assert(other);
+
+ /* Filter out invocations with bogus state */
+ if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT)
+ return;
+
+ /* Don't propagate state changes from the mount if we are already down */
+ if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
+ return;
+
+ /* Propagate start limit hit state */
+ if (other->start_limit_hit) {
+ automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT);
+ return;
+ }
+
+ /* Don't propagate anything if there's still a job queued */
+ if (other->job)
+ return;
+
+ /* The mount is successfully established */
+ if (IN_SET(MOUNT(other)->state, MOUNT_MOUNTED, MOUNT_REMOUNTING)) {
+ (void) automount_send_ready(a, a->tokens, 0);
- switch (state) {
- case MOUNT_MOUNTED:
- case MOUNT_REMOUNTING:
- automount_send_ready(a, a->tokens, 0);
r = automount_start_expire(a);
if (r < 0)
log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
- break;
- case MOUNT_DEAD:
- case MOUNT_UNMOUNTING:
- case MOUNT_MOUNTING_SIGTERM:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_FAILED:
- if (old_state != state)
- automount_send_ready(a, a->tokens, -ENODEV);
- (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
- break;
- default:
- break;
- }
- switch (state) {
- case MOUNT_DEAD:
- automount_send_ready(a, a->expire_tokens, 0);
- break;
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGTERM:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_FAILED:
- if (old_state != state)
- automount_send_ready(a, a->expire_tokens, -ENODEV);
- break;
- default:
- break;
+ automount_set_state(a, AUTOMOUNT_RUNNING);
}
- return 0;
+ /* The mount is in some unhappy state now, let's unfreeze any waiting clients */
+ if (IN_SET(MOUNT(other)->state,
+ MOUNT_DEAD, MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_FAILED)) {
+
+ (void) automount_send_ready(a, a->tokens, -ENODEV);
+
+ automount_set_state(a, AUTOMOUNT_WAITING);
+ }
}
static void automount_enter_waiting(Automount *a) {
@@ -699,6 +698,15 @@ static int automount_start_expire(Automount *a) {
return 0;
}
+static void automount_stop_expire(Automount *a) {
+ assert(a);
+
+ if (!a->expire_event_source)
+ return;
+
+ (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
+}
+
static void automount_enter_runnning(Automount *a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
struct stat st;
@@ -751,6 +759,7 @@ fail:
static int automount_start(Unit *u) {
Automount *a = AUTOMOUNT(u);
Unit *trigger;
+ int r;
assert(a);
assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
@@ -766,6 +775,12 @@ static int automount_start(Unit *u) {
return -ENOENT;
}
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
a->result = AUTOMOUNT_SUCCESS;
automount_enter_waiting(a);
return 1;
@@ -958,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
case autofs_ptype_expire_direct:
log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
- (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
+ automount_stop_expire(a);
r = set_ensure_allocated(&a->expire_tokens, NULL);
if (r < 0) {
@@ -1037,7 +1052,9 @@ static bool automount_supported(void) {
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
- [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
+ [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
+ [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
@@ -1050,9 +1067,6 @@ const UnitVTable automount_vtable = {
"Automount\0"
"Install\0",
- .no_alias = true,
- .no_instances = true,
-
.init = automount_init,
.load = automount_load,
.done = automount_done,
@@ -1072,6 +1086,8 @@ const UnitVTable automount_vtable = {
.check_gc = automount_check_gc,
+ .trigger_notify = automount_trigger_notify,
+
.reset_failed = automount_reset_failed,
.bus_vtable = bus_automount_vtable,
diff --git a/src/core/automount.h b/src/core/automount.h
index cf5b1cf994..76a201178e 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -26,6 +26,8 @@ typedef struct Automount Automount;
typedef enum AutomountResult {
AUTOMOUNT_SUCCESS,
AUTOMOUNT_FAILURE_RESOURCES,
+ AUTOMOUNT_FAILURE_START_LIMIT_HIT,
+ AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT,
_AUTOMOUNT_RESULT_MAX,
_AUTOMOUNT_RESULT_INVALID = -1
} AutomountResult;
@@ -53,7 +55,5 @@ struct Automount {
extern const UnitVTable automount_vtable;
-int automount_update_mount(Automount *a, MountState old_state, MountState state);
-
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;
diff --git a/src/core/busname.c b/src/core/busname.c
index f4f433340c..f03a95c24e 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -607,6 +607,7 @@ fail:
static int busname_start(Unit *u) {
BusName *n = BUSNAME(u);
+ int r;
assert(n);
@@ -632,6 +633,12 @@ static int busname_start(Unit *u) {
assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ busname_enter_dead(n, BUSNAME_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
n->result = BUSNAME_SUCCESS;
busname_enter_making(n);
@@ -1014,6 +1021,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_FAILURE_EXIT_CODE] = "exit-code",
[BUSNAME_FAILURE_SIGNAL] = "signal",
[BUSNAME_FAILURE_CORE_DUMP] = "core-dump",
+ [BUSNAME_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit",
};
@@ -1028,9 +1036,6 @@ const UnitVTable busname_vtable = {
"Install\0",
.private_section = "BusName",
- .no_alias = true,
- .no_instances = true,
-
.init = busname_init,
.done = busname_done,
.load = busname_load,
diff --git a/src/core/busname.h b/src/core/busname.h
index 52c4055dbb..a8562db458 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -32,6 +32,7 @@ typedef enum BusNameResult {
BUSNAME_FAILURE_EXIT_CODE,
BUSNAME_FAILURE_SIGNAL,
BUSNAME_FAILURE_CORE_DUMP,
+ BUSNAME_FAILURE_START_LIMIT_HIT,
BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT,
_BUSNAME_RESULT_MAX,
_BUSNAME_RESULT_INVALID = -1
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index d90b73b456..996efde22b 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1315,7 +1315,9 @@ int manager_setup_cgroup(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to watch control group inotify object: %m");
- r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
+ /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also
+ * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
+ r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-5);
if (r < 0)
return log_error_errno(r, "Failed to set priority of inotify event source: %m");
@@ -1461,6 +1463,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
assert(m);
assert(cgroup);
+ log_debug("Got cgroup empty notification for: %s", cgroup);
+
u = manager_get_unit_by_cgroup(m, cgroup);
if (!u)
return 0;
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index bb09a515f8..961340608d 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -149,7 +149,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 263955d874..3422a02d68 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -71,28 +71,42 @@ int bus_send_queued_message(Manager *m) {
return 0;
}
+int bus_forward_agent_released(Manager *m, const char *path) {
+ int r;
+
+ assert(m);
+ assert(path);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return 0;
+
+ if (!m->system_bus)
+ return 0;
+
+ /* If we are running a system instance we forward the agent message on the system bus, so that the user
+ * instances get notified about this, too */
+
+ r = sd_bus_emit_signal(m->system_bus,
+ "/org/freedesktop/systemd1/agent",
+ "org.freedesktop.systemd1.Agent",
+ "Released",
+ "s", path);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to propagate agent release message: %m");
+
+ return 1;
+}
+
static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- const char *cgroup, *me;
Manager *m = userdata;
+ const char *cgroup;
uid_t sender_uid;
- sd_bus *bus;
int r;
assert(message);
assert(m);
- /* ignore recursive events sent by us on the system/user bus */
- bus = sd_bus_message_get_bus(message);
- if (!sd_bus_is_server(bus)) {
- r = sd_bus_get_unique_name(bus, &me);
- if (r < 0)
- return r;
-
- if (streq_ptr(sd_bus_message_get_sender(message), me))
- return 0;
- }
-
/* only accept org.freedesktop.systemd1.Agent from UID=0 */
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
@@ -110,16 +124,6 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus
}
manager_notify_cgroup_empty(m, cgroup);
-
- /* if running as system-instance, forward under our name */
- if (MANAGER_IS_SYSTEM(m) && m->system_bus) {
- r = sd_bus_message_rewind(message, 1);
- if (r >= 0)
- r = sd_bus_send(m->system_bus, message, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to forward Released message: %m");
- }
-
return 0;
}
@@ -690,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
- if (MANAGER_IS_SYSTEM(m)) {
- /* When we run as system instance we get the Released
- * signal via a direct connection */
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
- return 0;
- }
- }
-
r = bus_setup_disconnected_match(m, bus);
if (r < 0)
return 0;
@@ -906,8 +891,8 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
- /* On kdbus or if we are a user instance we get the Released message via the system bus */
- if (MANAGER_IS_USER(m) || m->kdbus_fd >= 0) {
+ /* if we are a user instance we get the Released message via the system bus */
+ if (MANAGER_IS_USER(m)) {
r = sd_bus_add_match(
bus,
NULL,
@@ -990,7 +975,7 @@ static int bus_init_private(Manager *m) {
return 0;
strcpy(sa.un.sun_path, "/run/systemd/private");
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
+ salen = SOCKADDR_UN_LEN(sa.un);
} else {
size_t left = sizeof(sa.un.sun_path);
char *p = sa.un.sun_path;
diff --git a/src/core/dbus.h b/src/core/dbus.h
index e16a84fbb8..6baaffbd75 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -40,3 +40,5 @@ int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
+
+int bus_forward_agent_released(Manager *m, const char *path);
diff --git a/src/core/device.c b/src/core/device.c
index d01bec53d8..16e56efcc3 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -841,8 +841,6 @@ const UnitVTable device_vtable = {
"Device\0"
"Install\0",
- .no_instances = 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 ac2ac39892..5eb3f13695 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -271,7 +271,7 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
}
}
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = -errno;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index c4566f7709..1a8c03904c 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3427,10 +3427,10 @@ int config_parse_protect_system(
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
+ char *id = NULL;
unsigned c = 0;
int fd, r;
FILE *f;
- char *id = NULL;
assert(filename);
assert(*filename);
@@ -3452,7 +3452,6 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
* the names of this unit, but only if it is a valid
* unit name. */
name = basename(*filename);
-
if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
id = set_get(names, name);
@@ -3492,6 +3491,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
*_f = f;
*_final = id;
+
return 0;
}
@@ -3552,13 +3552,13 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
}
static int load_from_path(Unit *u, const char *path) {
- int r;
_cleanup_set_free_free_ Set *symlink_names = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *filename = NULL;
char *id = NULL;
Unit *merged;
struct stat st;
+ int r;
assert(u);
assert(path);
@@ -3597,18 +3597,14 @@ static int load_from_path(Unit *u, const char *path) {
r = -ENOENT;
else
r = open_follow(&filename, &f, symlink_names, &id);
+ if (r >= 0)
+ break;
+ filename = mfree(filename);
+ if (r != -ENOENT)
+ return r;
- if (r < 0) {
- filename = mfree(filename);
- if (r != -ENOENT)
- return r;
-
- /* Empty the symlink names for the next run */
- set_clear_free(symlink_names);
- continue;
- }
-
- break;
+ /* Empty the symlink names for the next run */
+ set_clear_free(symlink_names);
}
}
@@ -3616,6 +3612,11 @@ static int load_from_path(Unit *u, const char *path) {
/* Hmm, no suitable file found? */
return 0;
+ if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
+ log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
+ return -ELOOP;
+ }
+
merged = u;
r = merge_by_names(&merged, symlink_names, id);
if (r < 0)
diff --git a/src/core/manager.c b/src/core/manager.c
index bd00c224f4..e192cd475d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -87,6 +87,7 @@
#include "watchdog.h"
#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
+#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -94,6 +95,7 @@
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
@@ -484,11 +486,11 @@ static int manager_setup_signals(Manager *m) {
(void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
- /* Process signals a bit earlier than the rest of things, but
- * later than notify_fd processing, so that the notify
- * processing can still figure out to which process/service a
- * message belongs, before we reap the process. */
- r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the
+ * notify processing can still figure out to which process/service a message belongs, before we reap the
+ * process. Also, process this before handling cgroup notifications, so that we always collect child exit
+ * status information before detecting that there's no process in a cgroup. */
+ r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-6);
if (r < 0)
return r;
@@ -581,12 +583,12 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
- m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = -1;
+ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd =
+ m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd =
+ m->ask_password_inotify_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
- m->ask_password_inotify_fd = -1;
m->have_ask_password = -EINVAL; /* we don't know */
m->first_boot = -1;
@@ -703,7 +705,7 @@ static int manager_setup_notify(Manager *m) {
(void) unlink(m->notify_socket);
strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
@@ -722,8 +724,8 @@ static int manager_setup_notify(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to allocate notify event source: %m");
- /* Process signals a bit earlier than SIGCHLD, so that we can
- * still identify to which service an exit message belongs */
+ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which
+ * service an exit message belongs. */
r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7);
if (r < 0)
return log_error_errno(r, "Failed to set priority of notify event source: %m");
@@ -734,6 +736,79 @@ static int manager_setup_notify(Manager *m) {
return 0;
}
+static int manager_setup_cgroups_agent(Manager *m) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/cgroups-agent",
+ };
+ int r;
+
+ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
+ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
+ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
+ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
+ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
+ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
+ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
+ * we thus won't lose messages.
+ *
+ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
+ * to it. The system instance hence listens on this special socket, but the user instances listen on the system
+ * bus for these messages. */
+
+ if (m->test_run)
+ return 0;
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return 0;
+
+ if (cg_unified() > 0) /* We don't need this anymore on the unified hierarchy */
+ return 0;
+
+ if (m->cgroups_agent_fd < 0) {
+ _cleanup_close_ int fd = -1;
+
+ /* First free all secondary fields */
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
+
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
+
+ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE);
+
+ (void) unlink(sa.un.sun_path);
+
+ /* Only allow root to connect to this socket */
+ RUN_WITH_UMASK(0077)
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
+
+ m->cgroups_agent_fd = fd;
+ fd = -1;
+ }
+
+ if (!m->cgroups_agent_event_source) {
+ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
+
+ /* Process cgroups notifications early, but after having processed service notification messages or
+ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification,
+ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of
+ * cgroup inotify for the unified cgroup stuff. */
+ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
+
+ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
+ }
+
+ return 0;
+}
+
static int manager_setup_kdbus(Manager *m) {
_cleanup_free_ char *p = NULL;
@@ -944,12 +1019,14 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->signal_event_source);
sd_event_source_unref(m->notify_event_source);
+ sd_event_source_unref(m->cgroups_agent_event_source);
sd_event_source_unref(m->time_change_event_source);
sd_event_source_unref(m->jobs_in_progress_event_source);
sd_event_source_unref(m->run_queue_event_source);
safe_close(m->signal_fd);
safe_close(m->notify_fd);
+ safe_close(m->cgroups_agent_fd);
safe_close(m->time_change_fd);
safe_close(m->kdbus_fd);
@@ -1142,6 +1219,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (q < 0 && r == 0)
r = q;
+ q = manager_setup_cgroups_agent(m);
+ if (q < 0 && r == 0)
+ r = q;
+
/* We might have deserialized the kdbus control fd, but if we
* didn't, then let's create the bus now. */
manager_setup_kdbus(m);
@@ -1479,6 +1560,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
return n;
}
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ Manager *m = userdata;
+ char buf[PATH_MAX+1];
+ ssize_t n;
+
+ n = recv(fd, buf, sizeof(buf), 0);
+ if (n < 0)
+ return log_error_errno(errno, "Failed to read cgroups agent message: %m");
+ if (n == 0) {
+ log_error("Got zero-length cgroups agent message, ignoring.");
+ return 0;
+ }
+ if ((size_t) n >= sizeof(buf)) {
+ log_error("Got overly long cgroups agent message, ignoring.");
+ return 0;
+ }
+
+ if (memchr(buf, 0, n)) {
+ log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
+ return 0;
+ }
+ buf[n] = 0;
+
+ manager_notify_cgroup_empty(m, buf);
+ bus_forward_agent_released(m, buf);
+
+ return 0;
+}
+
static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
_cleanup_strv_free_ char **tags = NULL;
@@ -2135,11 +2245,10 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
- union sockaddr_union sa = PLYMOUTH_SOCKET;
-
- int n = 0;
+ static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *message = NULL;
_cleanup_close_ int fd = -1;
+ int n = 0;
/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
@@ -2165,7 +2274,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
return;
}
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
log_error_errno(errno, "connect() failed: %m");
@@ -2265,6 +2374,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "notify-socket=%s\n", m->notify_socket);
}
+ if (m->cgroups_agent_fd >= 0) {
+ int copy;
+
+ copy = fdset_put_dup(fds, m->cgroups_agent_fd);
+ if (copy < 0)
+ return copy;
+
+ fprintf(f, "cgroups-agent-fd=%i\n", copy);
+ }
+
if (m->kdbus_fd >= 0) {
int copy;
@@ -2432,6 +2551,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
free(m->notify_socket);
m->notify_socket = n;
+ } else if (startswith(l, "cgroups-agent-fd=")) {
+ int fd;
+
+ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_debug("Failed to parse cgroups agent fd: %s", l + 10);
+ else {
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
+ safe_close(m->cgroups_agent_fd);
+ m->cgroups_agent_fd = fdset_remove(fds, fd);
+ }
+
} else if (startswith(l, "kdbus-fd=")) {
int fd;
@@ -2552,6 +2682,10 @@ int manager_reload(Manager *m) {
if (q < 0 && r >= 0)
r = q;
+ q = manager_setup_cgroups_agent(m);
+ if (q < 0 && r >= 0)
+ r = q;
+
/* Third, fire things up! */
manager_coldplug(m);
diff --git a/src/core/manager.h b/src/core/manager.h
index 17f84e6963..4bccca75cb 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -132,6 +132,9 @@ struct Manager {
int notify_fd;
sd_event_source *notify_event_source;
+ int cgroups_agent_fd;
+ sd_event_source *cgroups_agent_event_source;
+
int signal_fd;
sd_event_source *signal_event_source;
diff --git a/src/core/mount.c b/src/core/mount.c
index cc07873b24..5a8c26b9e1 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -584,23 +584,6 @@ static int mount_load(Unit *u) {
return mount_verify(m);
}
-static int mount_notify_automount(Mount *m, MountState old_state, MountState state) {
- Unit *p;
- int r;
- Iterator i;
-
- assert(m);
-
- SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
- if (p->type == UNIT_AUTOMOUNT) {
- r = automount_update_mount(AUTOMOUNT(p), old_state, state);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
static void mount_set_state(Mount *m, MountState state) {
MountState old_state;
assert(m);
@@ -624,8 +607,6 @@ static void mount_set_state(Mount *m, MountState state) {
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
}
- mount_notify_automount(m, old_state, state);
-
if (state != old_state)
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
@@ -984,6 +965,7 @@ fail:
static int mount_start(Unit *u) {
Mount *m = MOUNT(u);
+ int r;
assert(m);
@@ -1002,6 +984,12 @@ static int mount_start(Unit *u) {
assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
m->reset_cpu_usage = true;
@@ -1821,7 +1809,8 @@ static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
[MOUNT_FAILURE_TIMEOUT] = "timeout",
[MOUNT_FAILURE_EXIT_CODE] = "exit-code",
[MOUNT_FAILURE_SIGNAL] = "signal",
- [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
+ [MOUNT_FAILURE_CORE_DUMP] = "core-dump",
+ [MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
@@ -1839,9 +1828,6 @@ const UnitVTable mount_vtable = {
"Install\0",
.private_section = "Mount",
- .no_alias = true,
- .no_instances = true,
-
.init = mount_init,
.load = mount_load,
.done = mount_done,
diff --git a/src/core/mount.h b/src/core/mount.h
index 3b343c6b1f..da529c44f4 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -39,6 +39,7 @@ typedef enum MountResult {
MOUNT_FAILURE_EXIT_CODE,
MOUNT_FAILURE_SIGNAL,
MOUNT_FAILURE_CORE_DUMP,
+ MOUNT_FAILURE_START_LIMIT_HIT,
_MOUNT_RESULT_MAX,
_MOUNT_RESULT_INVALID = -1
} MountResult;
diff --git a/src/core/path.c b/src/core/path.c
index 5e7b3eb234..0dd0d375d8 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -560,6 +560,7 @@ static void path_mkdir(Path *p) {
static int path_start(Unit *u) {
Path *p = PATH(u);
Unit *trigger;
+ int r;
assert(p);
assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
@@ -570,6 +571,12 @@ static int path_start(Unit *u) {
return -ENOENT;
}
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
path_mkdir(p);
p->result = PATH_SUCCESS;
@@ -739,6 +746,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
static const char* const path_result_table[_PATH_RESULT_MAX] = {
[PATH_SUCCESS] = "success",
[PATH_FAILURE_RESOURCES] = "resources",
+ [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
diff --git a/src/core/path.h b/src/core/path.h
index bbbcebd78e..4230c8fb99 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -62,6 +62,7 @@ static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
typedef enum PathResult {
PATH_SUCCESS,
PATH_FAILURE_RESOURCES,
+ PATH_FAILURE_START_LIMIT_HIT,
_PATH_RESULT_MAX,
_PATH_RESULT_INVALID = -1
} PathResult;
diff --git a/src/core/scope.c b/src/core/scope.c
index 7078d1f7e9..238f63a729 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -569,8 +569,6 @@ const UnitVTable scope_vtable = {
"Install\0",
.private_section = "Scope",
- .no_alias = true,
- .no_instances = true,
.can_transient = true,
.init = scope_init,
diff --git a/src/core/service.c b/src/core/service.c
index f7a3fcf2b9..7ebabca5d6 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1957,6 +1957,7 @@ fail:
static int service_start(Unit *u) {
Service *s = SERVICE(u);
+ int r;
assert(s);
@@ -1983,6 +1984,13 @@ static int service_start(Unit *u) {
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
+ /* Make sure we don't enter a busy loop of some kind. */
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
+ return r;
+ }
+
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
s->main_pid_known = false;
@@ -3266,6 +3274,7 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
[SERVICE_FAILURE_SIGNAL] = "signal",
[SERVICE_FAILURE_CORE_DUMP] = "core-dump",
[SERVICE_FAILURE_WATCHDOG] = "watchdog",
+ [SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
diff --git a/src/core/service.h b/src/core/service.h
index c7f1e81bdb..4af3d40439 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -86,6 +86,7 @@ typedef enum ServiceResult {
SERVICE_FAILURE_SIGNAL,
SERVICE_FAILURE_CORE_DUMP,
SERVICE_FAILURE_WATCHDOG,
+ SERVICE_FAILURE_START_LIMIT_HIT,
_SERVICE_RESULT_MAX,
_SERVICE_RESULT_INVALID = -1
} ServiceResult;
diff --git a/src/core/slice.c b/src/core/slice.c
index 63a77c9bca..c7700b8857 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -309,8 +309,6 @@ const UnitVTable slice_vtable = {
"Install\0",
.private_section = "Slice",
- .no_alias = true,
- .no_instances = true,
.can_transient = true,
.init = slice_init,
diff --git a/src/core/socket.c b/src/core/socket.c
index 7eeed068bd..d4b409ef53 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -100,7 +100,8 @@ static void socket_init(Unit *u) {
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
- RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500);
+ s->trigger_limit.interval = USEC_INFINITY;
+ s->trigger_limit.burst = (unsigned) -1;
}
static void socket_unwatch_control_pid(Socket *s) {
@@ -328,6 +329,25 @@ static int socket_add_extras(Socket *s) {
assert(s);
+ /* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit
+ * in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept()
+ * ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly
+ * and reliably. This is different for Accept=no, where the spawned service has to take the incoming traffic
+ * off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to
+ * process whatever is queued in one go, and thus should normally never have to be started frequently. This is
+ * different for Accept=yes where each connection is processed by a new service instance, and thus frequent
+ * service starts are typical. */
+
+ if (s->trigger_limit.interval == USEC_INFINITY)
+ s->trigger_limit.interval = 2 * USEC_PER_SEC;
+
+ if (s->trigger_limit.burst == (unsigned) -1) {
+ if (s->accept)
+ s->trigger_limit.burst = 200;
+ else
+ s->trigger_limit.burst = 20;
+ }
+
if (have_non_accept_socket(s)) {
if (!UNIT_DEREF(s->service)) {
@@ -620,8 +640,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
if (!isempty(s->user) || !isempty(s->group))
fprintf(f,
- "%sOwnerUser: %s\n"
- "%sOwnerGroup: %s\n",
+ "%sSocketUser: %s\n"
+ "%sSocketGroup: %s\n",
prefix, strna(s->user),
prefix, strna(s->group));
@@ -670,6 +690,12 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
}
+ fprintf(f,
+ "%sTriggerLimitIntervalSec: %s\n"
+ "%sTriggerLimitBurst: %u\n",
+ prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC),
+ prefix, s->trigger_limit.burst);
+
exec_context_dump(&s->exec_context, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
@@ -1271,11 +1297,13 @@ static int socket_open_fds(Socket *s) {
/* Apply the socket protocol */
switch(p->address.type) {
+
case SOCK_STREAM:
case SOCK_SEQPACKET:
if (p->socket->socket_protocol == IPPROTO_SCTP)
p->address.protocol = p->socket->socket_protocol;
break;
+
case SOCK_DGRAM:
if (p->socket->socket_protocol == IPPROTO_UDPLITE)
p->address.protocol = p->socket->socket_protocol;
@@ -1339,8 +1367,7 @@ static int socket_open_fds(Socket *s) {
}
break;
- case SOCKET_USB_FUNCTION:
- {
+ case SOCKET_USB_FUNCTION: {
_cleanup_free_ char *ep = NULL;
ep = path_make_absolute("ep0", p->path);
@@ -2057,6 +2084,7 @@ fail:
static int socket_start(Unit *u) {
Socket *s = SOCKET(u);
+ int r;
assert(s);
@@ -2101,6 +2129,12 @@ static int socket_start(Unit *u) {
assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
s->result = SOCKET_SUCCESS;
s->reset_cpu_usage = true;
@@ -2735,17 +2769,26 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
assert(u);
assert(other);
- /* Don't propagate state changes from the service if we are
- already down or accepting connections */
- if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept)
+ /* Filter out invocations with bogus state */
+ if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ return;
+
+ /* Don't propagate state changes from the service if we are already down */
+ if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING))
return;
+ /* We don't care for the service state if we are in Accept=yes mode */
+ if (s->accept)
+ return;
+
+ /* Propagate start limit hit state */
if (other->start_limit_hit) {
socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT);
return;
}
- if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ /* Don't propagate anything if there's still a job queued */
+ if (other->job)
return;
if (IN_SET(SERVICE(other)->state,
@@ -2818,6 +2861,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
[SOCKET_FAILURE_EXIT_CODE] = "exit-code",
[SOCKET_FAILURE_SIGNAL] = "signal",
[SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+ [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
[SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};
diff --git a/src/core/socket.h b/src/core/socket.h
index 2a4b1bb674..0f1ac69c6f 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -52,6 +52,7 @@ typedef enum SocketResult {
SOCKET_FAILURE_EXIT_CODE,
SOCKET_FAILURE_SIGNAL,
SOCKET_FAILURE_CORE_DUMP,
+ SOCKET_FAILURE_START_LIMIT_HIT,
SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
_SOCKET_RESULT_MAX,
diff --git a/src/core/swap.c b/src/core/swap.c
index d8802470d2..a532b15be8 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -814,6 +814,7 @@ fail:
static int swap_start(Unit *u) {
Swap *s = SWAP(u), *other;
+ int r;
assert(s);
@@ -842,6 +843,12 @@ static int swap_start(Unit *u) {
if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
return -EAGAIN;
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
s->result = SWAP_SUCCESS;
s->reset_cpu_usage = true;
@@ -1447,7 +1454,8 @@ static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
[SWAP_FAILURE_TIMEOUT] = "timeout",
[SWAP_FAILURE_EXIT_CODE] = "exit-code",
[SWAP_FAILURE_SIGNAL] = "signal",
- [SWAP_FAILURE_CORE_DUMP] = "core-dump"
+ [SWAP_FAILURE_CORE_DUMP] = "core-dump",
+ [SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
@@ -1465,9 +1473,6 @@ const UnitVTable swap_vtable = {
"Install\0",
.private_section = "Swap",
- .no_alias = true,
- .no_instances = true,
-
.init = swap_init,
.load = swap_load,
.done = swap_done,
diff --git a/src/core/swap.h b/src/core/swap.h
index ac7a63d81b..fbf66debdc 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -38,6 +38,7 @@ typedef enum SwapResult {
SWAP_FAILURE_EXIT_CODE,
SWAP_FAILURE_SIGNAL,
SWAP_FAILURE_CORE_DUMP,
+ SWAP_FAILURE_START_LIMIT_HIT,
_SWAP_RESULT_MAX,
_SWAP_RESULT_INVALID = -1
} SwapResult;
diff --git a/src/core/timer.c b/src/core/timer.c
index f8f5f4b2e4..3206296f09 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -599,6 +599,7 @@ static int timer_start(Unit *u) {
Timer *t = TIMER(u);
TimerValue *v;
Unit *trigger;
+ int r;
assert(t);
assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
@@ -609,6 +610,12 @@ static int timer_start(Unit *u) {
return -ENOENT;
}
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
t->last_trigger = DUAL_TIMESTAMP_NULL;
/* Reenable all timers that depend on unit activation time */
@@ -808,7 +815,8 @@ DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
[TIMER_SUCCESS] = "success",
- [TIMER_FAILURE_RESOURCES] = "resources"
+ [TIMER_FAILURE_RESOURCES] = "resources",
+ [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
diff --git a/src/core/timer.h b/src/core/timer.h
index 698e6da2f5..9c4b64f898 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -48,6 +48,7 @@ typedef struct TimerValue {
typedef enum TimerResult {
TIMER_SUCCESS,
TIMER_FAILURE_RESOURCES,
+ TIMER_FAILURE_START_LIMIT_HIT,
_TIMER_RESULT_MAX,
_TIMER_RESULT_INVALID = -1
} TimerResult;
diff --git a/src/core/unit.c b/src/core/unit.c
index 81cd7ee2b8..d8ab5781b0 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -193,7 +193,7 @@ int unit_add_name(Unit *u, const char *text) {
if (r < 0)
return r;
- if (i && unit_vtable[t]->no_instances)
+ if (i && !unit_type_may_template(t))
return -EINVAL;
/* Ensure that this unit is either instanced or not instanced,
@@ -202,7 +202,7 @@ int unit_add_name(Unit *u, const char *text) {
if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
return -EINVAL;
- if (unit_vtable[t]->no_alias && !set_isempty(u->names))
+ if (!unit_type_may_alias(t) && !set_isempty(u->names))
return -EEXIST;
if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
@@ -720,6 +720,9 @@ int unit_merge(Unit *u, Unit *other) {
if (!u->instance != !other->instance)
return -EINVAL;
+ if (!unit_type_may_alias(u->type)) /* Merging only applies to unit names that support aliases */
+ return -EEXIST;
+
if (other->load_state != UNIT_STUB &&
other->load_state != UNIT_NOT_FOUND)
return -EEXIST;
@@ -776,9 +779,9 @@ int unit_merge(Unit *u, Unit *other) {
}
int unit_merge_by_name(Unit *u, const char *name) {
+ _cleanup_free_ char *s = NULL;
Unit *other;
int r;
- _cleanup_free_ char *s = NULL;
assert(u);
assert(name);
@@ -1244,7 +1247,7 @@ int unit_load(Unit *u) {
fclose(u->transient_file);
u->transient_file = NULL;
- u->dropin_mtime = now(CLOCK_REALTIME);
+ u->fragment_mtime = now(CLOCK_REALTIME);
}
if (UNIT_VTABLE(u)->load) {
@@ -1459,7 +1462,7 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
unit_status_print_starting_stopping(u, t);
}
-static int unit_start_limit_test(Unit *u) {
+int unit_start_limit_test(Unit *u) {
assert(u);
if (ratelimit_test(&u->start_limit)) {
@@ -1485,7 +1488,6 @@ static int unit_start_limit_test(Unit *u) {
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
- int r;
assert(u);
@@ -1538,11 +1540,6 @@ int unit_start(Unit *u) {
if (!UNIT_VTABLE(u)->start)
return -EBADR;
- /* Make sure we don't enter a busy loop of some kind. */
- r = unit_start_limit_test(u);
- if (r < 0)
- return r;
-
/* We don't suppress calls to ->start() here when we are
* already starting, to allow this request to be used as a
* "hurry up" call, for example when the unit is in some "auto
@@ -2948,7 +2945,7 @@ int unit_coldplug(Unit *u) {
return 0;
}
-static bool fragment_mtime_changed(const char *path, usec_t mtime) {
+static bool fragment_mtime_newer(const char *path, usec_t mtime) {
struct stat st;
if (!path)
@@ -2960,7 +2957,7 @@ static bool fragment_mtime_changed(const char *path, usec_t mtime) {
if (mtime > 0)
/* For non-empty files check the mtime */
- return timespec_load(&st.st_mtim) != mtime;
+ return timespec_load(&st.st_mtim) > mtime;
else if (!null_or_empty(&st))
/* For masked files check if they are still so */
return true;
@@ -2971,32 +2968,24 @@ static bool fragment_mtime_changed(const char *path, usec_t mtime) {
bool unit_need_daemon_reload(Unit *u) {
_cleanup_strv_free_ char **t = NULL;
char **path;
- unsigned loaded_cnt, current_cnt;
assert(u);
- if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) ||
- fragment_mtime_changed(u->source_path, u->source_mtime))
+ if (fragment_mtime_newer(u->fragment_path, u->fragment_mtime))
return true;
- (void) unit_find_dropin_paths(u, &t);
- loaded_cnt = strv_length(t);
- current_cnt = strv_length(u->dropin_paths);
-
- if (loaded_cnt == current_cnt) {
- if (loaded_cnt == 0)
- return false;
+ if (fragment_mtime_newer(u->source_path, u->source_mtime))
+ return true;
- if (strv_overlap(u->dropin_paths, t)) {
- STRV_FOREACH(path, u->dropin_paths)
- if (fragment_mtime_changed(*path, u->dropin_mtime))
- return true;
+ (void) unit_find_dropin_paths(u, &t);
+ if (!strv_equal(u->dropin_paths, t))
+ return true;
- return false;
- }
- }
+ STRV_FOREACH(path, u->dropin_paths)
+ if (fragment_mtime_newer(*path, u->dropin_mtime))
+ return true;
- return true;
+ return false;
}
void unit_reset_failed(Unit *u) {
diff --git a/src/core/unit.h b/src/core/unit.h
index 78f950c051..08a927962d 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -417,12 +417,6 @@ struct UnitVTable {
/* The strings to print in status messages */
UnitStatusMessageFormats status_message_formats;
- /* Can units of this type have multiple names? */
- bool no_alias:1;
-
- /* Instances make no sense for this type */
- bool no_instances:1;
-
/* True if transient units of this type are OK */
bool can_transient:1;
};
@@ -618,6 +612,8 @@ static inline bool unit_supported(Unit *u) {
void unit_warn_if_dir_nonempty(Unit *u, const char* where);
int unit_fail_if_symlink(Unit *u, const char* where);
+int unit_start_limit_test(Unit *u);
+
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 41fc1993d5..01fdcfa909 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -847,7 +847,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd)
if (fd < 0)
return log_error_errno(errno, "Failed to create coredump socket: %m");
- if (connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to connect to coredump service: %m");
for (i = 0; i < n_iovec; i++) {
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 6f56066da8..d32e1d923e 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -262,7 +262,7 @@ static int fsck_progress_socket(void) {
if (fd < 0)
return log_warning_errno(errno, "socket(): %m");
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path);
safe_close(fd);
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 6f576b5ecf..343e3b1817 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -379,6 +379,7 @@ static int add_mount(
}
fprintf(f,
+ "\n"
"[Automount]\n"
"Where=%s\n",
where);
diff --git a/src/import/importd.c b/src/import/importd.c
index d2a5867a6e..956a82945c 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -677,7 +677,7 @@ static int manager_new(Manager **ret) {
(void) mkdir_parents_label(sa.un.sun_path, 0755);
(void) unlink(sa.un.sun_path);
- if (bind(m->notify_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index d301d4d79e..dc4e4667a9 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -330,7 +330,7 @@ int pull_verify(PullJob *main_job,
_cleanup_close_ int sig_file = -1;
const char *p, *line;
char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
- _cleanup_sigkill_wait_ pid_t pid = 0;
+ _cleanup_(sigkill_waitp) pid_t pid = 0;
bool gpg_home_created = false;
int r;
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index c9ce5c73be..7504326bff 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -3160,7 +3160,7 @@ int journal_file_open(
goto fail;
}
- /* The file is opened now successfully, thus we take possesion of any passed in fd. */
+ /* The file is opened now successfully, thus we take possession of any passed in fd. */
f->close_fd = true;
*ret = f;
@@ -3293,7 +3293,7 @@ int journal_file_open_reliably(
/* btrfs doesn't cope well with our write pattern and
* fragments heavily. Let's defrag all files we rotate */
- (void) chattr_path(p, false, FS_NOCOW_FL);
+ (void) chattr_path(p, 0, FS_NOCOW_FL);
(void) btrfs_defrag(p);
log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index f0959b6237..5e8a3e3200 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -208,13 +208,13 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
struct iovec *w;
uint64_t *l;
int i, j = 0;
- struct sockaddr_un sa = {
- .sun_family = AF_UNIX,
- .sun_path = "/run/systemd/journal/socket",
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/socket",
};
struct msghdr mh = {
- .msg_name = &sa,
- .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
+ .msg_name = (struct sockaddr*) &sa.sa,
+ .msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
ssize_t k;
bool have_syslog_identifier = false;
@@ -392,7 +392,7 @@ _public_ int sd_journal_perror(const char *message) {
}
_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
- union sockaddr_union sa = {
+ static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
@@ -408,7 +408,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index a445291a5e..0a1ce205c2 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -448,24 +448,24 @@ void server_process_native_file(
}
int server_open_native_socket(Server*s) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/socket",
+ };
static const int one = 1;
int r;
assert(s);
if (s->native_fd < 0) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/socket",
- };
-
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->native_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index e14d0ad980..8f82d2a838 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1696,7 +1696,7 @@ static int server_connect_notify(Server *s) {
if (sa.un.sun_path[0] == '@')
sa.un.sun_path[0] = 0;
- r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
+ r = connect(s->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "Failed to connect to notify socket: %m");
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 59352bcb3f..4ad16ee41c 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -700,23 +700,22 @@ fail:
}
int server_open_stdout_socket(Server *s) {
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/stdout",
+ };
int r;
assert(s);
if (s->stdout_fd < 0) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/stdout",
- };
-
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->stdout_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 5153fd0cce..0609b4b694 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -52,8 +52,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
.msg_iov = (struct iovec *) iovec,
.msg_iovlen = n_iovec,
.msg_name = (struct sockaddr*) &sa.sa,
- .msg_namelen = offsetof(union sockaddr_union, un.sun_path)
- + strlen("/run/systemd/journal/syslog"),
+ .msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
struct cmsghdr *cmsg;
union {
@@ -316,12 +315,12 @@ static void syslog_skip_date(char **buf) {
}
void server_process_syslog_message(
- Server *s,
- const char *buf,
- const struct ucred *ucred,
- const struct timeval *tv,
- const char *label,
- size_t label_len) {
+ Server *s,
+ const char *buf,
+ const struct ucred *ucred,
+ const struct timeval *tv,
+ const char *label,
+ size_t label_len) {
char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
@@ -365,14 +364,12 @@ void server_process_syslog_message(
if (identifier) {
syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier);
- if (syslog_identifier)
- IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
if (pid) {
syslog_pid = strjoina("SYSLOG_PID=", pid);
- if (syslog_pid)
- IOVEC_SET_STRING(iovec[n++], syslog_pid);
+ IOVEC_SET_STRING(iovec[n++], syslog_pid);
}
message = strjoina("MESSAGE=", buf);
@@ -383,24 +380,24 @@ void server_process_syslog_message(
}
int server_open_syslog_socket(Server *s) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/dev-log",
+ };
static const int one = 1;
int r;
assert(s);
if (s->syslog_fd < 0) {
- static const union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/dev-log",
- };
-
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
@@ -437,6 +434,7 @@ int server_open_syslog_socket(Server *s) {
void server_maybe_warn_forward_syslog_missed(Server *s) {
usec_t n;
+
assert(s);
if (s->n_forward_syslog_missed <= 0)
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 27c1dd346f..1cea68ad42 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -1942,7 +1942,7 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd
return 0;
fail:
- /* If we fail, make sure we don't take possession of the files we managed to make use of successfuly, and they
+ /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
* remain open */
ORDERED_HASHMAP_FOREACH(f, j->files, iterator)
f->close_fd = false;
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
index 4f7d4d8bf2..a21efc4d06 100644
--- a/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libsystemd-network/dhcp-identifier.c
@@ -31,6 +31,37 @@
#define SYSTEMD_PEN 43793
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
+int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) {
+ struct duid d;
+
+ assert_cc(sizeof(d.raw) >= MAX_DUID_LEN);
+ if (duid_len > MAX_DUID_LEN)
+ return -EINVAL;
+
+ switch (duid_type) {
+ case DUID_TYPE_LLT:
+ if (duid_len <= sizeof(d.llt))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_EN:
+ if (duid_len != sizeof(d.en))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_LL:
+ if (duid_len <= sizeof(d.ll))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_UUID:
+ if (duid_len != sizeof(d.uuid))
+ return -EINVAL;
+ break;
+ default:
+ /* accept unknown type in order to be forward compatible */
+ break;
+ }
+ return 0;
+}
+
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
sd_id128_t machine_id;
uint64_t hash;
diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h
index e6486b78f8..1cc0f9fb71 100644
--- a/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libsystemd-network/dhcp-identifier.h
@@ -26,7 +26,6 @@
#include "unaligned.h"
typedef enum DUIDType {
- DUID_TYPE_RAW = 0,
DUID_TYPE_LLT = 1,
DUID_TYPE_EN = 2,
DUID_TYPE_LL = 3,
@@ -40,27 +39,28 @@ typedef enum DUIDType {
*/
#define MAX_DUID_LEN 128
+/* https://tools.ietf.org/html/rfc3315#section-9.1 */
struct duid {
be16_t type;
union {
struct {
- /* DHCP6_DUID_LLT */
+ /* DUID_TYPE_LLT */
uint16_t htype;
uint32_t time;
uint8_t haddr[0];
} _packed_ llt;
struct {
- /* DHCP6_DUID_EN */
+ /* DUID_TYPE_EN */
uint32_t pen;
uint8_t id[8];
} _packed_ en;
struct {
- /* DHCP6_DUID_LL */
+ /* DUID_TYPE_LL */
int16_t htype;
uint8_t haddr[0];
} _packed_ ll;
struct {
- /* DHCP6_DUID_UUID */
+ /* DUID_TYPE_UUID */
sd_id128_t uuid;
} _packed_ uuid;
struct {
@@ -69,36 +69,6 @@ struct duid {
};
} _packed_;
+int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len);
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
-
-static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) {
- struct duid d;
-
- assert(duid_len > 0);
-
- switch (duid_type) {
- case DUID_TYPE_LLT:
- if (duid_len <= sizeof(d.llt))
- return -EINVAL;
- break;
- case DUID_TYPE_EN:
- if (duid_len != sizeof(d.en))
- return -EINVAL;
- break;
- case DUID_TYPE_LL:
- if (duid_len <= sizeof(d.ll))
- return -EINVAL;
- break;
- case DUID_TYPE_UUID:
- if (duid_len != sizeof(d.uuid))
- return -EINVAL;
- break;
- default:
- if (duid_len > sizeof(d.raw))
- return -EINVAL;
- /* accept unknown type in order to be forward compatible */
- break;
- }
- return 0;
-}
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 99b3a1d01f..182d08c50d 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -225,8 +225,6 @@ int config_parse_ifnames(const char *unit,
void *userdata) {
char ***sv = data;
- const char *word, *state;
- size_t l;
int r;
assert(filename);
@@ -234,22 +232,25 @@ int config_parse_ifnames(const char *unit,
assert(rvalue);
assert(data);
- FOREACH_WORD(word, l, rvalue, state) {
- char *n;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
- n = strndup(word, l);
- if (!n)
- return log_oom();
+ r = extract_first_word(&rvalue, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
- if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
+ if (!ascii_is_valid(word) || strlen(word) >= IFNAMSIZ) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- free(n);
return 0;
}
- r = strv_consume(sv, n);
+ r = strv_push(sv, word);
if (r < 0)
return log_oom();
+
+ word = NULL;
}
return 0;
@@ -380,28 +381,28 @@ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
_cleanup_free_ struct in_addr *addresses = NULL;
int size = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- _cleanup_free_ char *addr_str = NULL;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
struct in_addr *new_addresses;
int r;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
if (!new_addresses)
return -ENOMEM;
else
addresses = new_addresses;
- addr_str = strndup(word, len);
- if (!addr_str)
- return -ENOMEM;
-
- r = inet_pton(AF_INET, addr_str, &(addresses[size]));
+ r = inet_pton(AF_INET, word, &(addresses[size]));
if (r <= 0)
continue;
@@ -431,28 +432,28 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
_cleanup_free_ struct in6_addr *addresses = NULL;
int size = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- _cleanup_free_ char *addr_str = NULL;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
struct in6_addr *new_addresses;
int r;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
if (!new_addresses)
return -ENOMEM;
else
addresses = new_addresses;
- addr_str = strndup(word, len);
- if (!addr_str)
- return -ENOMEM;
-
- r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
+ r = inet_pton(AF_INET6, word, &(addresses[size]));
if (r <= 0)
continue;
@@ -493,29 +494,29 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
_cleanup_free_ struct sd_dhcp_route *routes = NULL;
size_t size = 0, allocated = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(ret_size);
assert(ret_allocated);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
- _cleanup_free_ char* entry = NULL;
+ /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
char *tok, *tok_end;
unsigned n;
int r;
- if (!GREEDY_REALLOC(routes, allocated, size + 1))
- return -ENOMEM;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
- entry = strndup(word, len);
- if (!entry)
+ if (!GREEDY_REALLOC(routes, allocated, size + 1))
return -ENOMEM;
- tok = entry;
+ tok = word;
/* get the subnet */
tok_end = strchr(tok, '/');
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 287b6e26fa..3846cf7476 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -115,14 +115,22 @@ static const uint8_t default_req_opts[] = {
SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
};
-static int client_receive_message_raw(sd_event_source *s, int fd,
- uint32_t revents, void *userdata);
-static int client_receive_message_udp(sd_event_source *s, int fd,
- uint32_t revents, void *userdata);
+static int client_receive_message_raw(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata);
+static int client_receive_message_udp(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata);
static void client_stop(sd_dhcp_client *client, int error);
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb,
- void *userdata) {
+int sd_dhcp_client_set_callback(
+ sd_dhcp_client *client,
+ sd_dhcp_client_callback_t cb,
+ void *userdata) {
assert_return(client, -EINVAL);
client->cb = cb;
@@ -171,8 +179,9 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
return 0;
}
-int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
- const struct in_addr *last_addr) {
+int sd_dhcp_client_set_request_address(
+ sd_dhcp_client *client,
+ const struct in_addr *last_addr) {
assert_return(client, -EINVAL);
assert_return (IN_SET(client->state, DHCP_STATE_INIT,
DHCP_STATE_STOPPED), -EBUSY);
@@ -196,8 +205,12 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
return 0;
}
-int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
- size_t addr_len, uint16_t arp_type) {
+int sd_dhcp_client_set_mac(
+ sd_dhcp_client *client,
+ const uint8_t *addr,
+ size_t addr_len,
+ uint16_t arp_type) {
+
DHCP_CLIENT_DONT_DESTROY(client);
bool need_restart = false;
@@ -234,8 +247,11 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
return 0;
}
-int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
- const uint8_t **data, size_t *data_len) {
+int sd_dhcp_client_get_client_id(
+ sd_dhcp_client *client,
+ uint8_t *type,
+ const uint8_t **data,
+ size_t *data_len) {
assert_return(client, -EINVAL);
assert_return(type, -EINVAL);
@@ -254,8 +270,12 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
return 0;
}
-int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
- const uint8_t *data, size_t data_len) {
+int sd_dhcp_client_set_client_id(
+ sd_dhcp_client *client,
+ uint8_t type,
+ const uint8_t *data,
+ size_t data_len) {
+
DHCP_CLIENT_DONT_DESTROY(client);
bool need_restart = false;
@@ -298,13 +318,32 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
return 0;
}
-int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
- uint16_t duid_type, uint8_t *duid, size_t duid_len) {
+/**
+ * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
+ * without further modification. Otherwise, if duid_type is supported, DUID
+ * is set based on that type. Otherwise, an error is returned.
+ */
+int sd_dhcp_client_set_iaid_duid(
+ sd_dhcp_client *client,
+ uint32_t iaid,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len) {
+
DHCP_CLIENT_DONT_DESTROY(client);
int r;
+ size_t len;
+
assert_return(client, -EINVAL);
- zero(client->client_id);
+ assert_return(duid_len == 0 || duid != NULL, -EINVAL);
+
+ if (duid != NULL) {
+ r = dhcp_validate_duid_len(duid_type, duid_len);
+ if (r < 0)
+ return r;
+ }
+ zero(client->client_id);
client->client_id.type = 255;
/* If IAID is not configured, generate it. */
@@ -317,22 +356,18 @@ int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
} else
client->client_id.ns.iaid = htobe32(iaid);
- /* If DUID is not configured, generate DUID-EN. */
- if (duid_len == 0) {
- r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid,
- &duid_len);
- if (r < 0)
- return r;
- } else {
- r = dhcp_validate_duid_len(client->client_id.type, duid_len);
- if (r < 0)
- return r;
+ if (duid != NULL) {
client->client_id.ns.duid.type = htobe16(duid_type);
memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
- duid_len += sizeof(client->client_id.ns.duid.type);
- }
+ len = sizeof(client->client_id.ns.duid.type) + duid_len;
+ } else if (duid_type == DUID_TYPE_EN) {
+ r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
+ if (r < 0)
+ return r;
+ } else
+ return -EOPNOTSUPP;
- client->client_id_len = sizeof(client->client_id.type) + duid_len +
+ client->client_id_len = sizeof(client->client_id.type) + len +
sizeof(client->client_id.ns.iaid);
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
@@ -344,8 +379,10 @@ int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
return 0;
}
-int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
- const char *hostname) {
+int sd_dhcp_client_set_hostname(
+ sd_dhcp_client *client,
+ const char *hostname) {
+
char *new_hostname = NULL;
assert_return(client, -EINVAL);
@@ -368,8 +405,10 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
return 0;
}
-int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
- const char *vci) {
+int sd_dhcp_client_set_vendor_class_identifier(
+ sd_dhcp_client *client,
+ const char *vci) {
+
char *new_vci = NULL;
assert_return(client, -EINVAL);
@@ -452,8 +491,13 @@ static void client_stop(sd_dhcp_client *client, int error) {
client_initialize(client);
}
-static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
- uint8_t type, size_t *_optlen, size_t *_optoffset) {
+static int client_message_init(
+ sd_dhcp_client *client,
+ DHCPPacket **ret,
+ uint8_t type,
+ size_t *_optlen,
+ size_t *_optoffset) {
+
_cleanup_free_ DHCPPacket *packet = NULL;
size_t optlen, optoffset, size;
be16_t max_size;
@@ -594,8 +638,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
return 0;
}
-static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset,
- const char *fqdn) {
+static int client_append_fqdn_option(
+ DHCPMessage *message,
+ size_t optlen,
+ size_t *optoffset,
+ const char *fqdn) {
+
uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
int r;
@@ -612,8 +660,11 @@ static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t
return r;
}
-static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
- size_t len) {
+static int dhcp_client_send_raw(
+ sd_dhcp_client *client,
+ DHCPPacket *packet,
+ size_t len) {
+
dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
INADDR_BROADCAST, DHCP_PORT_SERVER, len);
@@ -820,8 +871,11 @@ static int client_send_request(sd_dhcp_client *client) {
static int client_start(sd_dhcp_client *client);
-static int client_timeout_resend(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_resend(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
usec_t next_timeout = 0;
@@ -965,8 +1019,10 @@ error:
return 0;
}
-static int client_initialize_io_events(sd_dhcp_client *client,
- sd_event_io_handler_t io_callback) {
+static int client_initialize_io_events(
+ sd_dhcp_client *client,
+ sd_event_io_handler_t io_callback) {
+
int r;
assert(client);
@@ -1033,8 +1089,7 @@ error:
}
-static int client_initialize_events(sd_dhcp_client *client,
- sd_event_io_handler_t io_callback) {
+static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
client_initialize_io_events(client, io_callback);
client_initialize_time_events(client);
@@ -1074,8 +1129,7 @@ static int client_start(sd_dhcp_client *client) {
return client_start_delayed(client);
}
-static int client_timeout_expire(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
@@ -1115,8 +1169,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
return client_initialize_events(client, client_receive_message_raw);
}
-static int client_timeout_t1(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
@@ -1126,8 +1179,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec,
return client_initialize_time_events(client);
}
-static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
- size_t len) {
+static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
int r;
@@ -1178,8 +1230,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
return 0;
}
-static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
- size_t len) {
+static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
int r;
r = dhcp_option_parse(force, len, NULL, NULL, NULL);
@@ -1191,8 +1242,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
return 0;
}
-static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
- size_t len) {
+static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_free_ char *error_message = NULL;
int r;
@@ -1420,8 +1470,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return 0;
}
-static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
- int len) {
+static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
DHCP_CLIENT_DONT_DESTROY(client);
char time_string[FORMAT_TIMESPAN_MAX];
int r = 0, notify_event = 0;
@@ -1567,8 +1616,12 @@ error:
return r;
}
-static int client_receive_message_udp(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+static int client_receive_message_udp(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPMessage *message = NULL;
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
@@ -1645,8 +1698,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
return client_handle_message(client, message, len);
}
-static int client_receive_message_raw(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+static int client_receive_message_raw(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPPacket *packet = NULL;
uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index ee4fb4fc1e..4adb053a57 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -111,7 +111,10 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
-int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) {
+int sd_dhcp6_client_set_callback(
+ sd_dhcp6_client *client,
+ sd_dhcp6_client_callback_t cb,
+ void *userdata) {
assert_return(client, -EINVAL);
client->cb = cb;
@@ -131,7 +134,10 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
return 0;
}
-int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
+int sd_dhcp6_client_set_local_address(
+ sd_dhcp6_client *client,
+ const struct in6_addr *local_address) {
+
assert_return(client, -EINVAL);
assert_return(local_address, -EINVAL);
assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
@@ -180,20 +186,38 @@ static int client_ensure_duid(sd_dhcp6_client *client) {
return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
}
-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type,
- uint8_t *duid, size_t duid_len) {
+/**
+ * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
+ * without further modification. Otherwise, if duid_type is supported, DUID
+ * is set based on that type. Otherwise, an error is returned.
+ */
+int sd_dhcp6_client_set_duid(
+ sd_dhcp6_client *client,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len) {
+
int r;
assert_return(client, -EINVAL);
+ assert_return(duid_len == 0 || duid != NULL, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
- if (duid_len > 0) {
+ if (duid != NULL) {
r = dhcp_validate_duid_len(duid_type, duid_len);
if (r < 0)
return r;
+ }
+
+ if (duid != NULL) {
client->duid.type = htobe16(duid_type);
memcpy(&client->duid.raw.data, duid, duid_len);
- client->duid_len = duid_len + sizeof(client->duid.type);
- }
+ client->duid_len = sizeof(client->duid.type) + duid_len;
+ } else if (duid_type == DUID_TYPE_EN) {
+ r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
+ if (r < 0)
+ return r;
+ } else
+ return -EOPNOTSUPP;
return 0;
}
@@ -427,8 +451,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return 0;
}
-static int client_timeout_t2(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
assert_return(s, -EINVAL);
@@ -445,8 +468,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec,
return 0;
}
-static int client_timeout_t1(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
assert_return(s, -EINVAL);
@@ -463,8 +485,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec,
return 0;
}
-static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
enum DHCP6State state;
@@ -490,8 +511,7 @@ static usec_t client_timeout_compute_random(usec_t val) {
(random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
}
-static int client_timeout_resend(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
int r = 0;
sd_dhcp6_client *client = userdata;
usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
@@ -658,9 +678,11 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
return 0;
}
-static int client_parse_message(sd_dhcp6_client *client,
- DHCP6Message *message, size_t len,
- sd_dhcp6_lease *lease) {
+static int client_parse_message(
+ sd_dhcp6_client *client,
+ DHCP6Message *message,
+ size_t len,
+ sd_dhcp6_lease *lease) {
int r;
uint8_t *optval, *option, *id = NULL;
uint16_t optcode, status;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 04da94e7e3..ed5f94e136 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -836,7 +836,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
b->sockaddr.un.sun_family = AF_UNIX;
strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
- b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket");
+ b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);
return 0;
}
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index bd1c7f15ff..4da9dbfd63 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -458,9 +458,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (sockaddr.un.sun_path[0] == '@')
sockaddr.un.sun_path[0] = 0;
- msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
- if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
- msghdr.msg_namelen = sizeof(struct sockaddr_un);
+ msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
have_pid = pid != 0 && pid != getpid();
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index f56798674c..86d8dee867 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -207,11 +207,11 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
* and gives us too little data (so don't do that)
*/
padding = mempcpy(RTA_DATA(rta), data, data_length);
- else {
+
+ else
/* if no data was passed, make sure we still initialize the padding
note that we can have data_length > 0 (used by some containers) */
padding = RTA_DATA(rta);
- }
/* make sure also the padding at the end of the message is initialized */
padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
@@ -343,7 +343,7 @@ int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, c
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
- r = add_rtattr(m, type, &data, len);
+ r = add_rtattr(m, type, data, len);
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index f251536a89..09240c7b2a 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -111,6 +111,20 @@ int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
return 0;
}
+int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_table = table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
struct rtmsg *rtm;
@@ -126,6 +140,20 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
return 0;
}
+int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_family = family;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
struct rtmsg *rtm;
diff --git a/src/locale/language-fallback-map b/src/locale/language-fallback-map
index 6aadda091a..d0b02a6b98 100644
--- a/src/locale/language-fallback-map
+++ b/src/locale/language-fallback-map
@@ -3,6 +3,10 @@ en_AU en_AU:en_GB
en_IE en_IE:en_GB
en_NZ en_NZ:en_GB
en_ZA en_ZA:en_GB
+fr_BE fr_BE:fr_FR
+fr_CA fr_CA:fr_FR
+fr_CH fr_CH:fr_FR
+fr_LU fr_LU:fr_FR
it_CH it_CH:it_IT
mai_IN mai:hi
nds_DE nds:de
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index a281f99a34..0a84d75e24 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -265,6 +265,42 @@ static int property_get_docked(
return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
}
+static int property_get_current_sessions(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions));
+}
+
+static int property_get_current_inhibitors(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->inhibitors));
+}
+
static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
@@ -725,6 +761,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
m->seat0->positions[vtnr]->class != SESSION_GREETER)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
+ if (hashmap_size(m->sessions) >= m->sessions_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
+
audit_session_from_pid(leader, &audit_id);
if (audit_id > 0) {
/* Keep our session IDs and the audit session IDs in sync */
@@ -2442,6 +2481,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
+ if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max);
+
do {
id = mfree(id);
@@ -2512,6 +2554,13 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
+ SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 0, 0),
+ SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0),
+ SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 8552c464cc..6bd08adc05 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -34,4 +34,6 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
+Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max)
+Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max)
Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max)
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index a0e3ba2b7c..6c78e0dddc 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -317,7 +317,7 @@ int inhibitor_create_fifo(Inhibitor *i) {
if (r < 0)
return r;
- r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
+ r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10);
if (r < 0)
return r;
}
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 3cee10d009..f934a5326a 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -306,7 +306,7 @@ const sd_bus_vtable seat_vtable[] = {
SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index a8b1d5943d..d2f1f7bc62 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -897,7 +897,9 @@ int session_create_fifo(Session *s) {
if (r < 0)
return r;
- r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
+ /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
+ * sessions). */
+ r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
if (r < 0)
return r;
}
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index b73f9ea69e..af6392e025 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -245,7 +245,7 @@ const sd_bus_vtable user_vtable[] = {
SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/login/logind.c b/src/login/logind.c
index a48e2fc61e..caf149cfb7 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -62,7 +62,9 @@ static void manager_reset_config(Manager *m) {
m->idle_action = HANDLE_IGNORE;
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
- m->user_tasks_max = UINT64_C(12288);
+ m->user_tasks_max = 12288;
+ m->sessions_max = 8192;
+ m->inhibitors_max = 8192;
m->kill_user_processes = KILL_USER_PROCESSES;
@@ -686,7 +688,7 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
- r = sd_bus_attach_event(m->bus, m->event, 0);
+ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in
index 3c96def45d..32c0844cb6 100644
--- a/src/login/logind.conf.in
+++ b/src/login/logind.conf.in
@@ -32,4 +32,6 @@
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RemoveIPC=yes
+#InhibitorsMax=8192
+#SessionsMax=8192
#UserTasksMax=12288
diff --git a/src/login/logind.h b/src/login/logind.h
index 6748af3c07..90431eb4b0 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -133,6 +133,8 @@ struct Manager {
size_t runtime_dir_size;
uint64_t user_tasks_max;
+ uint64_t sessions_max;
+ uint64_t inhibitors_max;
};
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 40e246bb06..98dc201340 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -150,7 +150,7 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
if (fd < 0)
return -errno;
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
r = getpeercred(fd, &ucred);
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c
index b764bc43a0..0eed9b81bb 100644
--- a/src/machine/image-dbus.c
+++ b/src/machine/image-dbus.c
@@ -20,9 +20,11 @@
#include "alloc-util.h"
#include "bus-label.h"
#include "bus-util.h"
+#include "fd-util.h"
#include "image-dbus.h"
#include "io-util.h"
#include "machine-image.h"
+#include "process-util.h"
#include "strv.h"
#include "user-util.h"
@@ -33,13 +35,18 @@ int bus_image_method_remove(
void *userdata,
sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
Image *image = userdata;
Manager *m = image->userdata;
+ pid_t child;
int r;
assert(message);
assert(image);
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
@@ -54,11 +61,35 @@ int bus_image_method_remove(
if (r == 0)
return 1; /* Will call us back */
- r = image_remove(image);
- if (r < 0)
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ if (child == 0) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ r = image_remove(image);
+ if (r < 0) {
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_reply_method_return(message, NULL);
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
int bus_image_method_rename(
@@ -107,13 +138,19 @@ int bus_image_method_clone(
void *userdata,
sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
Image *image = userdata;
Manager *m = image->userdata;
const char *new_name;
int r, read_only;
+ pid_t child;
assert(message);
assert(image);
+ assert(m);
+
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
r = sd_bus_message_read(message, "sb", &new_name, &read_only);
if (r < 0)
@@ -136,13 +173,35 @@ int bus_image_method_clone(
if (r == 0)
return 1; /* Will call us back */
- r = image_clone(image, new_name, read_only);
- if (r == -EOPNOTSUPP)
- return sd_bus_reply_method_errnof(message, r, "Image cloning is currently only supported on btrfs file systems.");
- if (r < 0)
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ if (child == 0) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ r = image_clone(image, new_name, read_only);
+ if (r < 0) {
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_reply_method_return(message, NULL);
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
int bus_image_method_mark_read_only(
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 5121bfdd18..7b9aa66d63 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -1085,52 +1085,11 @@ finish:
return r;
}
-static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- MachineOperation *o = userdata;
- int r;
-
- assert(o);
- assert(si);
-
- o->pid = 0;
-
- if (si->si_code != CLD_EXITED) {
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
- goto fail;
- }
-
- if (si->si_status != EXIT_SUCCESS) {
- if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
- r = sd_bus_error_set_errnof(&error, r, "%m");
- else
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
-
- goto fail;
- }
-
- r = sd_bus_reply_method_return(o->message, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
-
- machine_operation_unref(o);
- return 0;
-
-fail:
- r = sd_bus_reply_method_error(o->message, &error);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
-
- machine_operation_unref(o);
- return 0;
-}
-
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
_cleanup_close_ int hostfd = -1;
Machine *m = userdata;
- MachineOperation *o;
bool copy_from;
pid_t child;
char *t;
@@ -1139,7 +1098,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
assert(message);
assert(m);
- if (m->n_operations >= MACHINE_OPERATIONS_MAX)
+ if (m->manager->n_operations >= OPERATIONS_MAX)
return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
if (m->class != MACHINE_CONTAINER)
@@ -1249,27 +1208,14 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
- /* Copying might take a while, hence install a watch the
- * child, and return */
+ /* Copying might take a while, hence install a watch on the child, and return */
- o = new0(MachineOperation, 1);
- if (!o)
- return log_oom();
-
- o->pid = child;
- o->message = sd_bus_message_ref(message);
- o->errno_fd = errno_pipe_fd[0];
- errno_pipe_fd[0] = -1;
-
- r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
+ r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]);
if (r < 0) {
- machine_operation_unref(o);
- return log_oom();
+ (void) sigkill_wait(child);
+ return r;
}
-
- LIST_PREPEND(operations, m->operations, o);
- m->n_operations++;
- o->machine = m;
+ errno_pipe_fd[0] = -1;
return 1;
}
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 7d4270a8ff..c1fae57084 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -89,7 +89,7 @@ void machine_free(Machine *m) {
assert(m);
while (m->operations)
- machine_operation_unref(m->operations);
+ operation_free(m->operations);
if (m->in_gc_queue)
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
@@ -596,28 +596,6 @@ int machine_open_terminal(Machine *m, const char *path, int mode) {
}
}
-MachineOperation *machine_operation_unref(MachineOperation *o) {
- if (!o)
- return NULL;
-
- sd_event_source_unref(o->event_source);
-
- safe_close(o->errno_fd);
-
- if (o->pid > 1)
- (void) kill(o->pid, SIGKILL);
-
- sd_bus_message_unref(o->message);
-
- if (o->machine) {
- LIST_REMOVE(operations, o->machine->operations, o);
- o->machine->n_operations--;
- }
-
- free(o);
- return NULL;
-}
-
void machine_release_unit(Machine *m) {
assert(m);
diff --git a/src/machine/machine.h b/src/machine/machine.h
index 1d8cc5911a..e5d75361a9 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -20,11 +20,11 @@
***/
typedef struct Machine Machine;
-typedef struct MachineOperation MachineOperation;
typedef enum KillWho KillWho;
#include "list.h"
#include "machined.h"
+#include "operation.h"
typedef enum MachineState {
MACHINE_OPENING, /* Machine is being registered */
@@ -49,17 +49,6 @@ enum KillWho {
_KILL_WHO_INVALID = -1
};
-#define MACHINE_OPERATIONS_MAX 64
-
-struct MachineOperation {
- Machine *machine;
- pid_t pid;
- sd_bus_message *message;
- int errno_fd;
- sd_event_source *event_source;
- LIST_FIELDS(MachineOperation, operations);
-};
-
struct Machine {
Manager *manager;
@@ -88,10 +77,9 @@ struct Machine {
int *netif;
unsigned n_netif;
- LIST_FIELDS(Machine, gc_queue);
+ LIST_HEAD(Operation, operations);
- MachineOperation *operations;
- unsigned n_operations;
+ LIST_FIELDS(Machine, gc_queue);
};
Machine* machine_new(Manager *manager, MachineClass class, const char *name);
@@ -109,8 +97,6 @@ void machine_release_unit(Machine *m);
MachineState machine_get_state(Machine *u);
-MachineOperation *machine_operation_unref(MachineOperation *o);
-
const char* machine_class_to_string(MachineClass t) _const_;
MachineClass machine_class_from_string(const char *s) _pure_;
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 5a68c4ceb2..1165ab5afa 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1076,6 +1076,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
static int copy_files(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ char *abs_host_path = NULL;
char *dest, *host_path, *container_path;
sd_bus *bus = userdata;
@@ -1099,19 +1100,28 @@ static int copy_files(int argc, char *argv[], void *userdata) {
host_path = abs_host_path;
}
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- copy_from ? "CopyFromMachine" : "CopyToMachine",
- &error,
- NULL,
+ copy_from ? "CopyFromMachine" : "CopyToMachine");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
"sss",
argv[1],
copy_from ? container_path : host_path,
copy_from ? host_path : container_path);
if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
return 0;
@@ -1393,7 +1403,6 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
}
static int remove_image(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
@@ -1402,19 +1411,27 @@ static int remove_image(int argc, char *argv[], void *userdata) {
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method(
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "RemoveImage",
- &error,
- NULL,
- "s", argv[i]);
- if (r < 0) {
- log_error("Could not remove image: %s", bus_error_message(&error, -r));
- return r;
- }
+ "RemoveImage");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "s", argv[i]);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
}
return 0;
@@ -1446,24 +1463,30 @@ static int rename_image(int argc, char *argv[], void *userdata) {
static int clone_image(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
sd_bus *bus = userdata;
int r;
polkit_agent_open_if_enabled();
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "CloneImage",
- &error,
- NULL,
- "ssb", argv[1], argv[2], arg_read_only);
- if (r < 0) {
- log_error("Could not clone image: %s", bus_error_message(&error, -r));
- return r;
- }
+ "CloneImage");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r));
return 0;
}
diff --git a/src/machine/machined.c b/src/machine/machined.c
index f2c1966a6b..f7ceb5e603 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -70,6 +70,11 @@ void manager_free(Manager *m) {
assert(m);
+ while (m->operations)
+ operation_free(m->operations);
+
+ assert(m->n_operations == 0);
+
while ((machine = hashmap_first(m->machines)))
machine_free(machine);
@@ -336,6 +341,9 @@ int manager_startup(Manager *m) {
static bool check_idle(void *userdata) {
Manager *m = userdata;
+ if (m->operations)
+ return false;
+
manager_gc(m, true);
return hashmap_isempty(m->machines);
diff --git a/src/machine/machined.h b/src/machine/machined.h
index e7d7dfdceb..7b9b148044 100644
--- a/src/machine/machined.h
+++ b/src/machine/machined.h
@@ -32,6 +32,7 @@ typedef struct Manager Manager;
#include "image-dbus.h"
#include "machine-dbus.h"
#include "machine.h"
+#include "operation.h"
struct Manager {
sd_event *event;
@@ -49,6 +50,9 @@ struct Manager {
LIST_HEAD(Machine, machine_gc_queue);
Machine *host_machine;
+
+ LIST_HEAD(Operation, operations);
+ unsigned n_operations;
};
Manager *manager_new(void);
diff --git a/src/machine/operation.c b/src/machine/operation.c
new file mode 100644
index 0000000000..e6ddc41a55
--- /dev/null
+++ b/src/machine/operation.c
@@ -0,0 +1,131 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "operation.h"
+#include "process-util.h"
+
+static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ Operation *o = userdata;
+ int r;
+
+ assert(o);
+ assert(si);
+
+ log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i",
+ o->pid,
+ sigchld_code_to_string(si->si_code), si->si_status);
+
+ o->pid = 0;
+
+ if (si->si_code != CLD_EXITED) {
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+ goto fail;
+ }
+
+ if (si->si_status != EXIT_SUCCESS) {
+ if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
+ r = sd_bus_error_set_errnof(&error, r, "%m");
+ else
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
+
+ goto fail;
+ }
+
+ r = sd_bus_reply_method_return(o->message, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ operation_free(o);
+ return 0;
+
+fail:
+ r = sd_bus_reply_method_error(o->message, &error);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ operation_free(o);
+ return 0;
+}
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) {
+ Operation *o;
+ int r;
+
+ assert(manager);
+ assert(child > 1);
+ assert(message);
+ assert(errno_fd >= 0);
+
+ o = new0(Operation, 1);
+ if (!o)
+ return -ENOMEM;
+
+ r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
+ if (r < 0) {
+ free(o);
+ return r;
+ }
+
+ o->pid = child;
+ o->message = sd_bus_message_ref(message);
+ o->errno_fd = errno_fd;
+
+ LIST_PREPEND(operations, manager->operations, o);
+ manager->n_operations++;
+ o->manager = manager;
+
+ if (machine) {
+ LIST_PREPEND(operations_by_machine, machine->operations, o);
+ o->machine = machine;
+ }
+
+ log_debug("Started new operation " PID_FMT ".", child);
+
+ /* At this point we took ownership of both the child and the errno file descriptor! */
+
+ return 0;
+}
+
+Operation *operation_free(Operation *o) {
+ if (!o)
+ return NULL;
+
+ sd_event_source_unref(o->event_source);
+
+ safe_close(o->errno_fd);
+
+ if (o->pid > 1)
+ (void) sigkill_wait(o->pid);
+
+ sd_bus_message_unref(o->message);
+
+ if (o->manager) {
+ LIST_REMOVE(operations, o->manager->operations, o);
+ o->manager->n_operations--;
+ }
+
+ if (o->machine)
+ LIST_REMOVE(operations_by_machine, o->machine->operations, o);
+
+ free(o);
+ return NULL;
+}
diff --git a/src/machine/operation.h b/src/machine/operation.h
new file mode 100644
index 0000000000..7ca47bc3af
--- /dev/null
+++ b/src/machine/operation.h
@@ -0,0 +1,47 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+
+#include "sd-bus.h"
+#include "sd-event.h"
+
+#include "list.h"
+
+typedef struct Operation Operation;
+
+#include "machined.h"
+
+#define OPERATIONS_MAX 64
+
+struct Operation {
+ Manager *manager;
+ Machine *machine;
+ pid_t pid;
+ sd_bus_message *message;
+ int errno_fd;
+ sd_event_source *event_source;
+ LIST_FIELDS(Operation, operations);
+ LIST_FIELDS(Operation, operations_by_machine);
+};
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd);
+Operation *operation_free(Operation *o);
diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h
index 8e1378ff40..af30decfe0 100644
--- a/src/network/networkd-address-pool.h
+++ b/src/network/networkd-address-pool.h
@@ -22,7 +22,9 @@
typedef struct AddressPool AddressPool;
#include "in-addr-util.h"
-#include "networkd.h"
+#include "list.h"
+
+typedef struct Manager Manager;
struct AddressPool {
Manager *manager;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 429319da6b..8b52a1f742 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -774,6 +774,54 @@ int config_parse_label(const char *unit,
return 0;
}
+int config_parse_lifetime(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Network *network = userdata;
+ _cleanup_address_free_ Address *n = NULL;
+ unsigned k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = address_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ if (STR_IN_SET(rvalue, "forever", "infinity")) {
+ n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
+ n = NULL;
+
+ return 0;
+ }
+
+ r = safe_atou(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (k != 0)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
+ else {
+ n->cinfo.ifa_prefered = k;
+ n = NULL;
+ }
+
+ return 0;
+}
+
bool address_is_ready(const Address *a) {
assert(a);
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 338f6eb9a2..784ab18b27 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -28,10 +28,12 @@ typedef struct Address Address;
#include "networkd-link.h"
#include "networkd-network.h"
-#include "networkd.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
+typedef struct Network Network;
+typedef struct Link Link;
+
struct Address {
Network *network;
unsigned section;
@@ -74,3 +76,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
int config_parse_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_broadcast(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_lifetime(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
index 70f0121d6d..b67a1f6d09 100644
--- a/src/network/networkd-conf.c
+++ b/src/network/networkd-conf.c
@@ -37,11 +37,10 @@ int manager_parse_config_file(Manager *m) {
}
static const char* const duid_type_table[_DUID_TYPE_MAX] = {
- [DUID_TYPE_RAW] = "raw",
[DUID_TYPE_LLT] = "link-layer-time",
[DUID_TYPE_EN] = "vendor",
[DUID_TYPE_LL] = "link-layer",
- [DUID_TYPE_UUID] = "uuid"
+ [DUID_TYPE_UUID] = "uuid",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType);
DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type");
@@ -58,69 +57,29 @@ int config_parse_duid_rawdata(
void *data,
void *userdata) {
- int r;
- char *cbyte;
- const char *pduid = rvalue;
- Manager *m = userdata;
- Network *n = userdata;
- DUIDType duidtype;
- uint16_t dhcp_duid_type = 0;
- uint8_t dhcp_duid[MAX_DUID_LEN];
- size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0;
+ DUID *ret = data;
+ uint8_t raw_data[MAX_DUID_LEN];
+ unsigned count = 0;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(userdata);
+ assert(ret);
- duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type;
-
- if (duidtype == _DUID_TYPE_INVALID)
- duidtype = DUID_TYPE_RAW;
-
- switch (duidtype) {
-
- case DUID_TYPE_LLT:
- /* RawData contains DUID-LLT link-layer address (offset 6) */
- duid_start_offset = 6;
- break;
-
- case DUID_TYPE_EN:
- /* RawData contains DUID-EN identifier (offset 4) */
- duid_start_offset = 4;
- break;
-
- case DUID_TYPE_LL:
- /* RawData contains DUID-LL link-layer address (offset 2) */
- duid_start_offset = 2;
- break;
-
- case DUID_TYPE_UUID:
- /* RawData specifies UUID (offset 0) - fall thru */
-
- case DUID_TYPE_RAW:
- /* First two bytes of RawData is DUID Type - fall thru */
-
- default:
- break;
- }
-
- if (duidtype != DUID_TYPE_RAW)
- dhcp_duid_type = (uint16_t) duidtype;
-
- /* RawData contains DUID in format " NN:NN:NN... " */
+ /* RawData contains DUID in format "NN:NN:NN..." */
for (;;) {
- int n1, n2;
+ int n1, n2, len, r;
uint32_t byte;
+ _cleanup_free_ char *cbyte = NULL;
- r = extract_first_word(&pduid, &cbyte, ":", 0);
+ r = extract_first_word(&rvalue, &cbyte, ":", 0);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue);
return 0;
}
if (r == 0)
break;
- if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) {
+ if (count >= MAX_DUID_LEN) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
return 0;
}
@@ -142,30 +101,11 @@ int config_parse_duid_rawdata(
}
byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2;
-
- /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */
- if (duidtype == DUID_TYPE_RAW && count < 2) {
- dhcp_duid_type |= (byte << (8 * (1 - count)));
- count++;
- continue;
- }
-
- dhcp_duid[duid_start_offset + dhcp_duid_len] = byte;
- dhcp_duid_len++;
- }
-
- if (ltype == DUID_CONFIG_SOURCE_GLOBAL) {
- m->duid_type = duidtype;
- m->dhcp_duid_type = dhcp_duid_type;
- m->dhcp_duid_len = dhcp_duid_len;
- memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
- } else {
- /* DUID_CONFIG_SOURCE_NETWORK */
- n->duid_type = duidtype;
- n->dhcp_duid_type = dhcp_duid_type;
- n->dhcp_duid_len = dhcp_duid_len;
- memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
+ raw_data[count++] = byte;
}
+ assert_cc(sizeof(raw_data) == sizeof(ret->raw_data));
+ memcpy(ret->raw_data, raw_data, count);
+ ret->raw_data_len = count;
return 0;
}
diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h
index 671e656d7b..c7bfb42a72 100644
--- a/src/network/networkd-conf.h
+++ b/src/network/networkd-conf.h
@@ -21,14 +21,29 @@
#include "networkd.h"
-typedef enum DuidConfigSource {
- DUID_CONFIG_SOURCE_GLOBAL = 0,
- DUID_CONFIG_SOURCE_NETWORK,
-} DuidConfigSource;
-
int manager_parse_config_file(Manager *m);
const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length);
-int config_parse_duid_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_duid_rawdata(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_duid_type(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata);
+int config_parse_duid_rawdata(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index c5b61abc9e..89926e8a7e 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -24,7 +24,7 @@
#include "dhcp-lease-internal.h"
#include "hostname-util.h"
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
@@ -628,28 +628,24 @@ int dhcp4_configure(Link *link) {
}
switch (link->network->dhcp_client_identifier) {
- case DHCP_CLIENT_ID_DUID:
+ case DHCP_CLIENT_ID_DUID: {
/* If configured, apply user specified DUID and/or IAID */
- if (link->network->duid_type != _DUID_TYPE_INVALID)
- r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
- link->network->iaid,
- link->network->dhcp_duid_type,
- link->network->dhcp_duid,
- link->network->dhcp_duid_len);
- else
- r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
- link->network->iaid,
- link->manager->dhcp_duid_type,
- link->manager->dhcp_duid,
- link->manager->dhcp_duid_len);
+ const DUID *duid = link_duid(link);
+
+ r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
if (r < 0)
return r;
break;
+ }
case DHCP_CLIENT_ID_MAC:
r = sd_dhcp_client_set_client_id(link->dhcp_client,
ARPHRD_ETHER,
(const uint8_t *) &link->mac,
- sizeof (link->mac));
+ sizeof(link->mac));
if (r < 0)
return r;
break;
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index d4b2fbfc57..ccca4e9522 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -23,7 +23,7 @@
#include "sd-dhcp6-client.h"
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
@@ -206,6 +206,7 @@ int dhcp6_request_address(Link *link) {
int dhcp6_configure(Link *link) {
sd_dhcp6_client *client = NULL;
int r;
+ const DUID *duid;
assert(link);
@@ -234,16 +235,11 @@ int dhcp6_configure(Link *link) {
if (r < 0)
goto error;
- if (link->network->duid_type != _DUID_TYPE_INVALID)
- r = sd_dhcp6_client_set_duid(client,
- link->network->dhcp_duid_type,
- link->network->dhcp_duid,
- link->network->dhcp_duid_len);
- else
- r = sd_dhcp6_client_set_duid(client,
- link->manager->dhcp_duid_type,
- link->manager->dhcp_duid,
- link->manager->dhcp_duid_len);
+ duid = link_duid(link);
+ r = sd_dhcp6_client_set_duid(client,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
if (r < 0)
goto error;
diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h
index 89b3e29405..84410714f5 100644
--- a/src/network/networkd-fdb.h
+++ b/src/network/networkd-fdb.h
@@ -19,10 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct FdbEntry FdbEntry;
+#include "list.h"
+#include "macro.h"
-#include "networkd-network.h"
-#include "networkd.h"
+typedef struct Network Network;
+typedef struct FdbEntry FdbEntry;
+typedef struct Link Link;
struct FdbEntry {
Network *network;
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
index afc71b4cb8..3fdfe74955 100644
--- a/src/network/networkd-gperf.gperf
+++ b/src/network/networkd-gperf.gperf
@@ -14,5 +14,5 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid_type)
-DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid)
+DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid.type)
+DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid)
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index e05fd3eea7..35c9b06473 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -21,7 +21,7 @@
#include <linux/if.h>
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int ipv4ll_address_lost(Link *link) {
_cleanup_address_free_ Address *address = NULL;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 5fc513bfda..c646af1f1a 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -28,9 +28,8 @@
#include "fileio.h"
#include "netlink-util.h"
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
#include "networkd-lldp-tx.h"
-#include "networkd-netdev.h"
#include "set.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -2880,6 +2879,8 @@ int link_update(Link *link, sd_netlink_message *m) {
}
if (link->dhcp_client) {
+ const DUID *duid = link_duid(link);
+
r = sd_dhcp_client_set_mac(link->dhcp_client,
(const uint8_t *) &link->mac,
sizeof (link->mac),
@@ -2887,23 +2888,18 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
- if (link->network->duid_type != _DUID_TYPE_INVALID)
- r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
- link->network->iaid,
- link->network->dhcp_duid_type,
- link->network->dhcp_duid,
- link->network->dhcp_duid_len);
- else
- r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
- link->network->iaid,
- link->manager->dhcp_duid_type,
- link->manager->dhcp_duid,
- link->manager->dhcp_duid_len);
+ r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
if (r < 0)
return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
}
if (link->dhcp6_client) {
+ const DUID* duid = link_duid(link);
+
r = sd_dhcp6_client_set_mac(link->dhcp6_client,
(const uint8_t *) &link->mac,
sizeof (link->mac),
@@ -2916,16 +2912,10 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
- if (link->network->duid_type != _DUID_TYPE_INVALID)
- r = sd_dhcp6_client_set_duid(link->dhcp6_client,
- link->network->dhcp_duid_type,
- link->network->dhcp_duid,
- link->network->dhcp_duid_len);
- else
- r = sd_dhcp6_client_set_duid(link->dhcp6_client,
- link->manager->dhcp_duid_type,
- link->manager->dhcp_duid,
- link->manager->dhcp_duid_len);
+ r = sd_dhcp6_client_set_duid(link->dhcp6_client,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
if (r < 0)
return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index f2a64ca9b5..86139be557 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -21,14 +21,17 @@
#include <endian.h>
+#include "sd-bus.h"
#include "sd-dhcp-client.h"
#include "sd-dhcp-server.h"
#include "sd-dhcp6-client.h"
#include "sd-ipv4ll.h"
#include "sd-lldp.h"
#include "sd-ndisc.h"
+#include "sd-netlink.h"
-typedef struct Link Link;
+#include "list.h"
+#include "set.h"
typedef enum LinkState {
LINK_STATE_PENDING,
@@ -54,11 +57,11 @@ typedef enum LinkOperationalState {
_LINK_OPERSTATE_INVALID = -1
} LinkOperationalState;
-#include "networkd-address.h"
-#include "networkd-network.h"
-#include "networkd.h"
+typedef struct Manager Manager;
+typedef struct Network Network;
+typedef struct Address Address;
-struct Link {
+typedef struct Link {
Manager *manager;
int n_ref;
@@ -122,7 +125,7 @@ struct Link {
Hashmap *bound_by_links;
Hashmap *bound_to_links;
-};
+} Link;
Link *link_unref(Link *link);
Link *link_ref(Link *link);
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
index 6bde04bc32..03b694c3f1 100644
--- a/src/network/networkd-lldp-tx.c
+++ b/src/network/networkd-lldp-tx.c
@@ -21,15 +21,18 @@
#include <inttypes.h>
#include <string.h>
+#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"
-#include "networkd-lldp-tx.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "unaligned.h"
+#include "networkd.h"
+#include "networkd-lldp-tx.h"
+
#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index d355aaa19c..5dcd4df536 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -1037,7 +1037,7 @@ int manager_new(Manager **ret) {
if (r < 0)
return r;
- m->duid_type = _DUID_TYPE_INVALID;
+ m->duid.type = DUID_TYPE_EN;
*ret = m;
m = NULL;
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 4577292e44..b22c58bfe5 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -24,7 +24,7 @@
#include "sd-ndisc.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 6b9cbcded6..7913b0088e 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "extract-word.h"
#include "missing.h"
#include "networkd-netdev-bond.h"
#include "string-table.h"
diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h
index cb6baea24f..b941edb344 100644
--- a/src/network/networkd-netdev-bond.h
+++ b/src/network/networkd-netdev-bond.h
@@ -20,8 +20,7 @@
***/
#include "in-addr-util.h"
-
-typedef struct Bond Bond;
+#include "list.h"
#include "networkd-netdev.h"
@@ -106,7 +105,7 @@ typedef struct ArpIpTarget {
LIST_FIELDS(struct ArpIpTarget, arp_ip_target);
} ArpIpTarget;
-struct Bond {
+typedef struct Bond {
NetDev meta;
BondMode mode;
@@ -133,8 +132,9 @@ struct Bond {
int n_arp_ip_targets;
ArpIpTarget *arp_ip_targets;
-};
+} Bond;
+DEFINE_NETDEV_CAST(BOND, Bond);
extern const NetDevVTable bond_vtable;
const char *bond_mode_to_string(BondMode d) _const_;
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 3f91b2eaea..3e44dd7960 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -22,6 +22,7 @@
#include "missing.h"
#include "netlink-util.h"
+#include "networkd.h"
#include "networkd-netdev-bridge.h"
/* callback for brige netdev's parameter set */
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index 3f6f1d0502..b921439f02 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -19,11 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct Bridge Bridge;
-
#include "networkd-netdev.h"
-struct Bridge {
+typedef struct Bridge {
NetDev meta;
int mcast_querier;
@@ -31,6 +29,7 @@ struct Bridge {
usec_t forward_delay;
usec_t hello_time;
usec_t max_age;
-};
+} Bridge;
+DEFINE_NETDEV_CAST(BRIDGE, Bridge);
extern const NetDevVTable bridge_vtable;
diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h
index 42da62ebe4..efe302267e 100644
--- a/src/network/networkd-netdev-dummy.h
+++ b/src/network/networkd-netdev-dummy.h
@@ -19,12 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct Dummy Dummy;
-
#include "networkd-netdev.h"
-struct Dummy {
+typedef struct Dummy {
NetDev meta;
-};
+} Dummy;
+DEFINE_NETDEV_CAST(DUMMY, Dummy);
extern const NetDevVTable dummy_vtable;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 15a787a9e3..1ebd0fdf20 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -1,11 +1,17 @@
%{
#include <stddef.h>
#include "conf-parser.h"
-#include "networkd-netdev.h"
-#include "networkd-netdev-tunnel.h"
+#include "network-internal.h"
#include "networkd-netdev-bond.h"
+#include "networkd-netdev-ipvlan.h"
#include "networkd-netdev-macvlan.h"
-#include "network-internal.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-bridge.h"
+#include "networkd-netdev.h"
%}
struct ConfigPerfItem;
%null_strings
diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h
index 4bd0b67866..10d4079844 100644
--- a/src/network/networkd-netdev-ipvlan.h
+++ b/src/network/networkd-netdev-ipvlan.h
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct IPVlan IPVlan;
-
#include "missing.h"
#include "networkd-netdev.h"
@@ -31,12 +29,13 @@ typedef enum IPVlanMode {
_NETDEV_IPVLAN_MODE_INVALID = -1
} IPVlanMode;
-struct IPVlan {
+typedef struct IPVlan {
NetDev meta;
IPVlanMode mode;
-};
+} IPVlan;
+DEFINE_NETDEV_CAST(IPVLAN, IPVlan);
extern const NetDevVTable ipvlan_vtable;
const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h
index 622ef9ef53..3663f4f051 100644
--- a/src/network/networkd-netdev-macvlan.h
+++ b/src/network/networkd-netdev-macvlan.h
@@ -38,6 +38,8 @@ struct MacVlan {
MacVlanMode mode;
};
+DEFINE_NETDEV_CAST(MACVLAN, MacVlan);
+DEFINE_NETDEV_CAST(MACVTAP, MacVlan);
extern const NetDevVTable macvlan_vtable;
extern const NetDevVTable macvtap_vtable;
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index 0d41f80a3c..7d31e7b687 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct Tunnel Tunnel;
+#include "in-addr-util.h"
#include "networkd-netdev.h"
@@ -37,7 +37,7 @@ typedef enum IPv6FlowLabel {
_NETDEV_IPV6_FLOWLABEL_INVALID = -1,
} IPv6FlowLabel;
-struct Tunnel {
+typedef struct Tunnel {
NetDev meta;
uint8_t encap_limit;
@@ -56,8 +56,17 @@ struct Tunnel {
bool pmtudisc;
bool copy_dscp;
-};
-
+} Tunnel;
+
+DEFINE_NETDEV_CAST(IPIP, Tunnel);
+DEFINE_NETDEV_CAST(GRE, Tunnel);
+DEFINE_NETDEV_CAST(GRETAP, Tunnel);
+DEFINE_NETDEV_CAST(IP6GRE, Tunnel);
+DEFINE_NETDEV_CAST(IP6GRETAP, Tunnel);
+DEFINE_NETDEV_CAST(SIT, Tunnel);
+DEFINE_NETDEV_CAST(VTI, Tunnel);
+DEFINE_NETDEV_CAST(VTI6, Tunnel);
+DEFINE_NETDEV_CAST(IP6TNL, Tunnel);
extern const NetDevVTable ipip_vtable;
extern const NetDevVTable sit_vtable;
extern const NetDevVTable vti_vtable;
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 32917fe6d5..088a4d8d32 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -17,10 +17,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/if.h>
-#include <sys/ioctl.h>
+#include <fcntl.h>
#include <linux/if_tun.h>
+#include <net/if.h>
#include <netinet/if_ether.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "alloc-util.h"
#include "fd-util.h"
diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h
index cbb7ee05a6..120f00a353 100644
--- a/src/network/networkd-netdev-tuntap.h
+++ b/src/network/networkd-netdev-tuntap.h
@@ -34,5 +34,7 @@ struct TunTap {
bool vnet_hdr;
};
+DEFINE_NETDEV_CAST(TUN, TunTap);
+DEFINE_NETDEV_CAST(TAP, TunTap);
extern const NetDevVTable tun_vtable;
extern const NetDevVTable tap_vtable;
diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h
index ae5785783c..e69bfbc8f0 100644
--- a/src/network/networkd-netdev-veth.h
+++ b/src/network/networkd-netdev-veth.h
@@ -30,4 +30,5 @@ struct Veth {
struct ether_addr *mac_peer;
};
+DEFINE_NETDEV_CAST(VETH, Veth);
extern const NetDevVTable veth_vtable;
diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h
index 1de6a1cc36..73aacf4a0f 100644
--- a/src/network/networkd-netdev-vlan.h
+++ b/src/network/networkd-netdev-vlan.h
@@ -31,4 +31,5 @@ struct VLan {
uint64_t id;
};
+DEFINE_NETDEV_CAST(VLAN, VLan);
extern const NetDevVTable vlan_vtable;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index dabbd97c87..724f9861be 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -23,8 +23,10 @@
#include "conf-parser.h"
#include "alloc-util.h"
+#include "extract-word.h"
#include "parse-util.h"
#include "missing.h"
+
#include "networkd-link.h"
#include "networkd-netdev-vxlan.h"
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index a4bb44635a..4614c66fd1 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -55,6 +55,7 @@ struct VxLan {
struct ifla_vxlan_port_range port_range;
};
+DEFINE_NETDEV_CAST(VXLAN, VxLan);
extern const NetDevVTable vxlan_vtable;
int config_parse_vxlan_group_address(const char *unit,
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 7ea825fcb4..20244c0309 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -19,15 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "list.h"
-
-typedef struct NetDev NetDev;
-typedef struct NetDevVTable NetDevVTable;
+#include "sd-netlink.h"
-#include "networkd-link.h"
-#include "networkd.h"
+#include "list.h"
+#include "time-util.h"
typedef struct netdev_join_callback netdev_join_callback;
+typedef struct Link Link;
struct netdev_join_callback {
sd_netlink_message_handler_t callback;
@@ -78,7 +76,10 @@ typedef enum NetDevCreateType {
_NETDEV_CREATE_INVALID = -1,
} NetDevCreateType;
-struct NetDev {
+typedef struct Manager Manager;
+typedef struct Condition Condition;
+
+typedef struct NetDev {
Manager *manager;
int n_ref;
@@ -99,20 +100,9 @@ struct NetDev {
int ifindex;
LIST_HEAD(netdev_join_callback, callbacks);
-};
+} NetDev;
-#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-vxlan.h"
-
-struct NetDevVTable {
+typedef struct NetDevVTable {
/* How much memory does an object of this unit type need */
size_t object_size;
@@ -144,14 +134,14 @@ struct NetDevVTable {
/* verify that compulsory configuration options were specified */
int (*config_verify)(NetDev *netdev, const char *filename);
-};
+} NetDevVTable;
extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
#define NETDEV_VTABLE(n) netdev_vtable[(n)->kind]
/* For casting a netdev into the various netdev kinds */
-#define DEFINE_CAST(UPPERCASE, MixedCase) \
+#define DEFINE_NETDEV_CAST(UPPERCASE, MixedCase) \
static inline MixedCase* UPPERCASE(NetDev *n) { \
if (_unlikely_(!n || n->kind != NETDEV_KIND_##UPPERCASE)) \
return NULL; \
@@ -162,27 +152,6 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
/* For casting the various netdev kinds into a netdev */
#define NETDEV(n) (&(n)->meta)
-DEFINE_CAST(BRIDGE, Bridge);
-DEFINE_CAST(BOND, Bond);
-DEFINE_CAST(VLAN, VLan);
-DEFINE_CAST(MACVLAN, MacVlan);
-DEFINE_CAST(MACVTAP, MacVlan);
-DEFINE_CAST(IPVLAN, IPVlan);
-DEFINE_CAST(VXLAN, VxLan);
-DEFINE_CAST(IPIP, Tunnel);
-DEFINE_CAST(GRE, Tunnel);
-DEFINE_CAST(GRETAP, Tunnel);
-DEFINE_CAST(IP6GRE, Tunnel);
-DEFINE_CAST(IP6GRETAP, Tunnel);
-DEFINE_CAST(SIT, Tunnel);
-DEFINE_CAST(VTI, Tunnel);
-DEFINE_CAST(VTI6, Tunnel);
-DEFINE_CAST(IP6TNL, Tunnel);
-DEFINE_CAST(VETH, Veth);
-DEFINE_CAST(DUMMY, Dummy);
-DEFINE_CAST(TUN, TunTap);
-DEFINE_CAST(TAP, TunTap);
-
int netdev_load(Manager *manager);
void netdev_drop(NetDev *netdev);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 654d6a0316..51e750b299 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -65,12 +65,14 @@ Address.Address, config_parse_address,
Address.Peer, config_parse_address, 0, 0
Address.Broadcast, config_parse_broadcast, 0, 0
Address.Label, config_parse_label, 0, 0
+Address.PreferredLifetime, config_parse_lifetime, 0, 0
Route.Gateway, config_parse_gateway, 0, 0
Route.Destination, config_parse_destination, 0, 0
Route.Source, config_parse_destination, 0, 0
Route.Metric, config_parse_route_priority, 0, 0
Route.Scope, config_parse_route_scope, 0, 0
Route.PreferredSource, config_parse_preferred_src, 0, 0
+Route.Table, config_parse_route_table, 0, 0
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
@@ -83,8 +85,8 @@ DHCP.Hostname, config_parse_hostname,
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
-DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid_type)
-DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid)
+DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type)
+DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 2ebcdfa744..206c270e50 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -131,7 +131,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->ipv6_accept_ra = -1;
network->ipv6_dad_transmits = -1;
network->ipv6_hop_limit = -1;
- network->duid_type = _DUID_TYPE_INVALID;
+ network->duid.type = _DUID_TYPE_INVALID;
network->proxy_arp = -1;
r = config_parse(NULL, filename, file,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 15417f4828..ff2414efdd 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -19,18 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-bus.h"
+#include "udev.h"
+
#include "condition.h"
+#include "dhcp-identifier.h"
+#include "hashmap.h"
#include "resolve-util.h"
-typedef struct Network Network;
-
-#include "dhcp-identifier.h"
#include "networkd-address.h"
#include "networkd-fdb.h"
#include "networkd-netdev.h"
#include "networkd-route.h"
#include "networkd-util.h"
-#include "networkd.h"
#define DHCP_ROUTE_METRIC 1024
#define IPV4LL_ROUTE_METRIC 2048
@@ -67,6 +68,16 @@ typedef enum LLDPMode {
_LLDP_MODE_INVALID = -1,
} LLDPMode;
+typedef struct DUID {
+ /* Value of Type in [DHCP] section */
+ DUIDType type;
+
+ uint8_t raw_data_len;
+ uint8_t raw_data[MAX_DUID_LEN];
+} DUID;
+
+typedef struct Manager Manager;
+
struct Network {
Manager *manager;
@@ -147,12 +158,7 @@ struct Network {
struct ether_addr *mac;
unsigned mtu;
uint32_t iaid;
- /* Value of Type in [DUID] section */
- DUIDType duid_type;
- /* DUID type code - RFC 3315 */
- uint16_t dhcp_duid_type;
- size_t dhcp_duid_len;
- uint8_t dhcp_duid[MAX_DUID_LEN];
+ DUID duid;
LLDPMode lldp_mode; /* LLDP reception */
bool lldp_emit; /* LLDP transmission */
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index bda2707e6d..43f37266d8 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -451,6 +451,10 @@ int route_configure(Route *route, Link *link,
r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
+
+ r = sd_rtnl_message_route_set_family(req, route->family);
+ if (r < 0)
+ return log_error_errno(r, "Could not set route family: %m");
}
if (route->dst_prefixlen) {
@@ -494,7 +498,26 @@ int route_configure(Route *route, Link *link,
r = sd_rtnl_message_route_set_flags(req, route->flags);
if (r < 0)
- return log_error_errno(r, "Colud not set flags: %m");
+ return log_error_errno(r, "Could not set flags: %m");
+
+ if (route->table != RT_TABLE_DEFAULT) {
+
+ if (route->table < 256) {
+ r = sd_rtnl_message_route_set_table(req, route->table);
+ if (r < 0)
+ return log_error_errno(r, "Could not set route table: %m");
+ } else {
+
+ r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
+ if (r < 0)
+ return log_error_errno(r, "Could not set route table: %m");
+
+ /* Table attribute to allow more than 256. */
+ r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_TABLE attribute: %m");
+ }
+ }
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
@@ -777,3 +800,42 @@ int config_parse_route_scope(const char *unit,
return 0;
}
+
+int config_parse_route_table(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ _cleanup_route_free_ Route *n = NULL;
+ Network *network = userdata;
+ uint32_t k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ n->table = k;
+
+ n = NULL;
+
+ return 0;
+}
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index a4a4bf2653..84d74992c9 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -22,7 +22,6 @@
typedef struct Route Route;
#include "networkd-network.h"
-#include "networkd.h"
struct Route {
Network *network;
@@ -37,7 +36,7 @@ struct Route {
unsigned char protocol; /* RTPROT_* */
unsigned char tos;
uint32_t priority; /* note that ip(8) calls this 'metric' */
- unsigned char table;
+ uint32_t table;
unsigned char pref;
unsigned flags;
@@ -74,3 +73,4 @@ int config_parse_preferred_src(const char *unit, const char *filename, unsigned
int config_parse_destination(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_route_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_route_scope(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_route_table(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 72a2438ac8..ab512f0d08 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -24,19 +24,29 @@
#include "sd-bus.h"
#include "sd-event.h"
#include "sd-netlink.h"
+#include "udev.h"
+#include "dhcp-identifier.h"
#include "hashmap.h"
#include "list.h"
-#include "udev.h"
-typedef struct Manager Manager;
-
-#include "dhcp-identifier.h"
#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-vxlan.h"
#include "networkd-network.h"
#include "networkd-util.h"
+extern const char* const network_dirs[];
+
struct Manager {
sd_netlink *rtnl;
sd_event *event;
@@ -63,17 +73,15 @@ struct Manager {
usec_t network_dirs_ts_usec;
- /* Value of Type in [DUID] section */
- DUIDType duid_type;
- /* DUID type code - RFC 3315 */
- uint16_t dhcp_duid_type;
- size_t dhcp_duid_len;
- uint8_t dhcp_duid[MAX_DUID_LEN];
+ DUID duid;
};
-extern const char* const network_dirs[];
-
-/* Manager */
+static inline const DUID* link_duid(const Link *link) {
+ if (link->network->duid.type != _DUID_TYPE_INVALID)
+ return &link->network->duid;
+ else
+ return &link->manager->duid;
+}
extern const sd_bus_vtable manager_vtable[];
diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c
new file mode 100644
index 0000000000..9bd30b82c6
--- /dev/null
+++ b/src/network/test-networkd-conf.c
@@ -0,0 +1,91 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "hexdecoct.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+
+#include "networkd-conf.h"
+#include "networkd-network.h"
+
+static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) {
+ DUIDType actual = 0;
+ int r;
+
+ r = config_parse_duid_type("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ log_info_errno(r, "\"%s\" → %d (%m)", rvalue, actual);
+ assert_se(r == ret);
+ assert_se(expected == actual);
+}
+
+static void test_config_parse_duid_type(void) {
+ test_config_parse_duid_type_one("", 0, 0);
+ test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT);
+ test_config_parse_duid_type_one("vendor", 0, DUID_TYPE_EN);
+ test_config_parse_duid_type_one("link-layer", 0, DUID_TYPE_LL);
+ test_config_parse_duid_type_one("uuid", 0, DUID_TYPE_UUID);
+ test_config_parse_duid_type_one("foo", 0, 0);
+}
+
+static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) {
+ DUID actual = {};
+ int r;
+ _cleanup_free_ char *d = NULL;
+
+ r = config_parse_duid_rawdata("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ d = hexmem(actual.raw_data, actual.raw_data_len);
+ log_info_errno(r, "\"%s\" → \"%s\" (%m)",
+ rvalue, strnull(d));
+ assert_se(r == ret);
+ if (expected) {
+ assert_se(actual.raw_data_len == expected->raw_data_len);
+ assert_se(memcmp(actual.raw_data, expected->raw_data, expected->raw_data_len) == 0);
+ }
+}
+
+#define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80"
+
+#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80}
+
+static void test_config_parse_duid_rawdata(void) {
+ test_config_parse_duid_rawdata_one("", 0, &(DUID){});
+ test_config_parse_duid_rawdata_one("00:11:22:33:44:55:66:77", 0,
+ &(DUID){0, 8, {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}});
+ test_config_parse_duid_rawdata_one("00:11:22:", 0,
+ &(DUID){0, 3, {0x00,0x11,0x22}});
+ test_config_parse_duid_rawdata_one("000:11:22", 0, &(DUID){}); /* error, output is all zeros */
+ test_config_parse_duid_rawdata_one("00:111:22", 0, &(DUID){});
+ test_config_parse_duid_rawdata_one("0:1:2:3:4:5:6:7", 0,
+ &(DUID){0, 8, {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}});
+ test_config_parse_duid_rawdata_one("11::", 0, &(DUID){0, 1, {0x11}}); /* FIXME: should this be an error? */
+ test_config_parse_duid_rawdata_one("abcdef", 0, &(DUID){});
+ test_config_parse_duid_rawdata_one(BYTES_0_128, 0, &(DUID){});
+ test_config_parse_duid_rawdata_one(BYTES_0_128 + 2, 0, &(DUID){0, 128, BYTES_1_128});
+}
+
+int main(int argc, char **argv) {
+ log_parse_environment();
+ log_open();
+
+ test_config_parse_duid_type();
+ test_config_parse_duid_rawdata();
+
+ return 0;
+}
diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c
index e291758969..17eab9772e 100644
--- a/src/reply-password/reply-password.c
+++ b/src/reply-password/reply-password.c
@@ -26,14 +26,12 @@
#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "socket-util.h"
#include "string-util.h"
#include "util.h"
static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
+ union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
@@ -43,7 +41,7 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0)
+ if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to send: %m");
return 0;
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index 706f8c14ed..ea04e58d61 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -810,7 +810,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
switch (t->state) {
case DNS_TRANSACTION_SUCCESS: {
- /* We found a successfuly reply, merge it into the answer */
+ /* We found a successfully reply, merge it into the answer */
r = dns_answer_extend(&q->answer, t->answer);
if (r < 0)
goto fail;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 081131ede0..a4a67623e7 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -1804,7 +1804,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* - For unsigned SOA/NS we get the matching DS
* - For unsigned CNAME/DNAME/DS we get the parent SOA RR
* - For other unsigned RRs we get the matching SOA RR
- * - For SOA/NS/DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
+ * - For SOA/NS queries with no matching response RR, and no NSEC/NSEC3, the DS RR
+ * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
* - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR
*/
@@ -2038,32 +2039,42 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
return r;
if (r > 0) {
const char *name;
+ uint16_t type = 0;
name = dns_resource_key_name(t->key);
- /* If this was a SOA or NS request, then this
- * indicates that we are not at a zone apex, hence ask
- * the parent name instead. If this was a DS request,
- * then it's signed when the parent zone is signed,
- * hence ask the parent in that case, too. */
+ /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this
+ * could also be used as indication that we are not at a zone apex, but in real world setups there are
+ * too many broken DNS servers (Hello, incapdns.net!) where non-terminal zones return NXDOMAIN even
+ * though they have further children. If this was a DS request, then it's signed when the parent zone
+ * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR,
+ * to see if that is signed. */
- if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) {
+ if (t->key->type == DNS_TYPE_DS) {
r = dns_name_parent(&name);
- if (r < 0)
- return r;
- if (r > 0)
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).",
+ if (r > 0) {
+ type = DNS_TYPE_SOA;
+ log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty DS response).",
t->id, dns_resource_key_name(t->key));
- else
+ } else
name = NULL;
- } else
+
+ } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) {
+
+ type = DNS_TYPE_DS;
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).",
+ t->id, dns_resource_key_name(t->key));
+
+ } else {
+ type = DNS_TYPE_SOA;
log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).",
t->id, dns_resource_key_name(t->key));
+ }
if (name) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
- soa = dns_resource_key_new(t->key->class, DNS_TYPE_SOA, name);
+ soa = dns_resource_key_new(t->key->class, type, name);
if (!soa)
return -ENOMEM;
@@ -2317,11 +2328,12 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
}
static int dns_transaction_requires_nsec(DnsTransaction *t) {
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsTransaction *dt;
const char *name;
+ uint16_t type = 0;
Iterator i;
int r;
- char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(t);
@@ -2355,22 +2367,25 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
name = dns_resource_key_name(t->key);
- if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) {
+ if (t->key->type == DNS_TYPE_DS) {
- /* We got a negative reply for this SOA/NS lookup? If
- * so, then we are not at a zone apex, and thus should
- * look at the result of the parent SOA lookup.
- *
- * We got a negative reply for this DS lookup? DS RRs
- * are signed when their parent zone is signed, hence
- * also check the parent SOA in this case. */
+ /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed,
+ * hence check the parent SOA in this case. */
r = dns_name_parent(&name);
if (r < 0)
return r;
if (r == 0)
return true;
- }
+
+ type = DNS_TYPE_SOA;
+
+ } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS))
+ /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */
+ type = DNS_TYPE_DS;
+ else
+ /* For all other negative replies, check for the SOA lookup */
+ type = DNS_TYPE_SOA;
/* For all other RRs we check the SOA on the same level to see
* if it's signed. */
@@ -2379,7 +2394,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dt->key->class != t->key->class)
continue;
- if (dt->key->type != DNS_TYPE_SOA)
+ if (dt->key->type != type)
continue;
r = dns_name_equal(dns_resource_key_name(dt->key), name);
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 6805873f9e..4a4bd8d3b8 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -431,7 +431,7 @@ static int create_socket(char **name) {
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
RUN_WITH_UMASK(0177) {
- if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
}
diff --git a/src/shared/install.c b/src/shared/install.c
index 931d3e2907..cc36da1853 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -66,8 +66,56 @@ typedef struct {
OrderedHashmap *have_processed;
} InstallContext;
+typedef enum {
+ PRESET_UNKNOWN,
+ PRESET_ENABLE,
+ PRESET_DISABLE,
+} PresetAction;
+
+typedef struct {
+ char *pattern;
+ PresetAction action;
+} PresetRule;
+
+typedef struct {
+ PresetRule *rules;
+ size_t n_rules;
+} Presets;
+
+static inline void presets_freep(Presets *p) {
+ size_t i;
+
+ if (!p)
+ return;
+
+ for (i = 0; i < p->n_rules; i++)
+ free(p->rules[i].pattern);
+
+ free(p->rules);
+ p->n_rules = 0;
+}
+
static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret);
+bool unit_type_may_alias(UnitType type) {
+ return IN_SET(type,
+ UNIT_SERVICE,
+ UNIT_SOCKET,
+ UNIT_TARGET,
+ UNIT_DEVICE,
+ UNIT_TIMER,
+ UNIT_PATH);
+}
+
+bool unit_type_may_template(UnitType type) {
+ return IN_SET(type,
+ UNIT_SERVICE,
+ UNIT_SOCKET,
+ UNIT_TARGET,
+ UNIT_TIMER,
+ UNIT_PATH);
+}
+
static int in_search_path(const LookupPaths *p, const char *path) {
_cleanup_free_ char *parent = NULL;
char **i;
@@ -898,6 +946,36 @@ fail:
return r;
}
+static int config_parse_alias(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ const char *name;
+ UnitType type;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ name = basename(filename);
+ type = unit_name_to_type(name);
+ if (!unit_type_may_alias(type))
+ return log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Aliases are not allowed for %s units, ignoring.",
+ unit_type_to_string(type));
+
+ return config_parse_strv(unit, filename, line, section, section_line,
+ lvalue, ltype, rvalue, data, userdata);
+}
+
static int config_parse_also(
const char *unit,
const char *filename,
@@ -954,6 +1032,7 @@ static int config_parse_default_instance(
void *userdata) {
UnitFileInstallInfo *i = data;
+ const char *name;
char *printed;
int r;
@@ -961,6 +1040,15 @@ static int config_parse_default_instance(
assert(lvalue);
assert(rvalue);
+ name = basename(filename);
+ if (unit_name_is_valid(name, UNIT_NAME_INSTANCE))
+ /* When enabling an instance, we might be using a template unit file,
+ * but we should ignore DefaultInstance silently. */
+ return 0;
+ if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
+ return log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "DefaultInstance only makes sense for template units, ignoring.");
+
r = install_full_printf(i, rvalue, &printed);
if (r < 0)
return r;
@@ -983,7 +1071,7 @@ static int unit_file_load(
SearchFlags flags) {
const ConfigTableItem items[] = {
- { "Install", "Alias", config_parse_strv, 0, &info->aliases },
+ { "Install", "Alias", config_parse_alias, 0, &info->aliases },
{ "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
{ "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
{ "Install", "DefaultInstance", config_parse_default_instance, 0, info },
@@ -991,6 +1079,8 @@ static int unit_file_load(
{}
};
+ const char *name;
+ UnitType type;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_close_ int fd = -1;
struct stat st;
@@ -1000,6 +1090,12 @@ static int unit_file_load(
assert(info);
assert(path);
+ name = basename(path);
+ type = unit_name_to_type(name);
+ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
+ !unit_type_may_template(type))
+ return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
+
if (!(flags & SEARCH_LOAD)) {
r = lstat(path, &st);
if (r < 0)
@@ -2367,17 +2463,16 @@ int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *
return 1;
}
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
+static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
+ _cleanup_(presets_freep) Presets ps = {};
+ size_t n_allocated = 0;
_cleanup_strv_free_ char **files = NULL;
char **p;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
-
- if (!unit_name_is_valid(name, UNIT_NAME_ANY))
- return -EINVAL;
+ assert(presets);
if (scope == UNIT_FILE_SYSTEM)
r = conf_files_list(&files, ".preset", root_dir,
@@ -2394,8 +2489,11 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
"/usr/local/lib/systemd/user-preset",
"/usr/lib/systemd/user-preset",
NULL);
- else
- return 1; /* Default is "enable" */
+ else {
+ *presets = (Presets){};
+
+ return 0;
+ }
if (r < 0)
return r;
@@ -2403,6 +2501,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
STRV_FOREACH(p, files) {
_cleanup_fclose_ FILE *f;
char line[LINE_MAX];
+ int n = 0;
f = fopen(*p, "re");
if (!f) {
@@ -2413,10 +2512,12 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
}
FOREACH_LINE(line, f, return -errno) {
+ PresetRule rule = {};
const char *parameter;
char *l;
l = strstrip(line);
+ n++;
if (isempty(l))
continue;
@@ -2425,31 +2526,87 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
parameter = first_word(l, "enable");
if (parameter) {
- if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
- log_debug("Preset file says enable %s.", name);
- return 1;
- }
+ char *pattern;
- continue;
+ pattern = strdup(parameter);
+ if (!pattern)
+ return -ENOMEM;
+
+ rule = (PresetRule) {
+ .pattern = pattern,
+ .action = PRESET_ENABLE,
+ };
}
parameter = first_word(l, "disable");
if (parameter) {
- if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
- log_debug("Preset file says disable %s.", name);
- return 0;
- }
+ char *pattern;
+
+ pattern = strdup(parameter);
+ if (!pattern)
+ return -ENOMEM;
+
+ rule = (PresetRule) {
+ .pattern = pattern,
+ .action = PRESET_DISABLE,
+ };
+ }
+ if (rule.action) {
+ if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
+ return -ENOMEM;
+
+ ps.rules[ps.n_rules++] = rule;
continue;
}
- log_debug("Couldn't parse line '%s'", l);
+ log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
}
}
- /* Default is "enable" */
- log_debug("Preset file doesn't say anything about %s, enabling.", name);
- return 1;
+ *presets = ps;
+ ps = (Presets){};
+
+ return 0;
+}
+
+static int query_presets(const char *name, const Presets presets) {
+ PresetAction action = PRESET_UNKNOWN;
+ size_t i;
+
+ if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ for (i = 0; i < presets.n_rules; i++)
+ if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
+ action = presets.rules[i].action;
+ break;
+ }
+
+ switch (action) {
+ case PRESET_UNKNOWN:
+ log_debug("Preset files don't specify rule for %s. Enabling.", name);
+ return 1;
+ case PRESET_ENABLE:
+ log_debug("Preset files say enable %s.", name);
+ return 1;
+ case PRESET_DISABLE:
+ log_debug("Preset files say disable %s.", name);
+ return 0;
+ default:
+ assert_not_reached("invalid preset action");
+ }
+}
+
+int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
+ _cleanup_(presets_freep) Presets presets = {};
+ int r;
+
+ r = read_presets(scope, root_dir, &presets);
+ if (r < 0)
+ return r;
+
+ return query_presets(name, presets);
}
static int execute_preset(
@@ -2505,6 +2662,7 @@ static int preset_prepare_one(
LookupPaths *paths,
UnitFilePresetMode mode,
const char *name,
+ Presets presets,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -2515,7 +2673,7 @@ static int preset_prepare_one(
install_info_find(minus, name))
return 0;
- r = unit_file_query_preset(scope, paths->root_dir, name);
+ r = query_presets(name, presets);
if (r < 0)
return r;
@@ -2545,6 +2703,7 @@ int unit_file_preset(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_(presets_freep) Presets presets = {};
const char *config_path;
char **i;
int r;
@@ -2559,11 +2718,12 @@ int unit_file_preset(
config_path = runtime ? paths.runtime_config : paths.persistent_config;
- STRV_FOREACH(i, files) {
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
- return -EINVAL;
+ r = read_presets(scope, root_dir, &presets);
+ if (r < 0)
+ return r;
- r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes);
+ STRV_FOREACH(i, files) {
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, presets, changes, n_changes);
if (r < 0)
return r;
}
@@ -2582,6 +2742,7 @@ int unit_file_preset_all(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_(presets_freep) Presets presets = {};
const char *config_path = NULL;
char **i;
int r;
@@ -2596,6 +2757,10 @@ int unit_file_preset_all(
config_path = runtime ? paths.runtime_config : paths.persistent_config;
+ r = read_presets(scope, root_dir, &presets);
+ if (r < 0)
+ return r;
+
STRV_FOREACH(i, paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@@ -2619,7 +2784,7 @@ int unit_file_preset_all(
continue;
/* we don't pass changes[] in, because we want to handle errors on our own */
- r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, NULL, 0);
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, presets, NULL, 0);
if (r == -ERFKILL)
r = unit_file_changes_add(changes, n_changes,
UNIT_FILE_IS_MASKED, de->d_name, NULL);
diff --git a/src/shared/install.h b/src/shared/install.h
index 4ffc5a21f2..5812447c5b 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -138,6 +138,9 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
return !strv_isempty(i->also);
}
+bool unit_type_may_alias(UnitType type) _const_;
+bool unit_type_may_template(UnitType type) _const_;
+
int unit_file_enable(
UnitFileScope scope,
bool runtime,
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index bebfc40efe..529d89ee2a 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -423,7 +423,7 @@ int image_remove(Image *i) {
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
- (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (r < 0)
return r;
@@ -487,7 +487,7 @@ int image_rename(Image *i, const char *new_name) {
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
- * time we take possesion of it */
+ * time we take possession of it */
r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
if (r < 0)
return r;
@@ -505,7 +505,7 @@ int image_rename(Image *i, const char *new_name) {
(void) read_attr_path(i->path, &file_attr);
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
/* fall through */
@@ -538,7 +538,7 @@ int image_rename(Image *i, const char *new_name) {
/* Restore the immutable bit, if it was set before */
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(new_path, true, FS_IMMUTABLE_FL);
+ (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
free(i->path);
i->path = new_path;
@@ -588,7 +588,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
- * time we take possesion of it */
+ * time we take possession of it */
r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
if (r < 0)
return r;
@@ -603,13 +603,21 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_SUBVOLUME:
case IMAGE_DIRECTORY:
+ /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
+ * directory.*/
+
new_path = strjoina("/var/lib/machines/", new_name);
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+ if (r == -EOPNOTSUPP) {
+ /* No btrfs snapshots supported, create a normal directory then. */
- /* Enable "subtree" quotas for the copy, if we didn't
- * copy any quota from the source. */
- (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+ r = copy_directory(i->path, new_path, false);
+ if (r >= 0)
+ (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
+ } else if (r >= 0)
+ /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
+ (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
break;
@@ -670,7 +678,7 @@ int image_read_only(Image *i, bool b) {
a read-only subvolume, but at least something, and
we can read the value back.*/
- r = chattr_path(i->path, b, FS_IMMUTABLE_FL);
+ r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
if (r < 0)
return r;
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 1157a0c72e..52b4db8875 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -400,28 +400,19 @@ static int resolve_remote(Connection *c) {
union sockaddr_union sa = {};
const char *node, *service;
- socklen_t salen;
int r;
if (path_is_absolute(arg_remote_host)) {
sa.un.sun_family = AF_UNIX;
- strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1);
- sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
-
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
-
- return connection_start(c, &sa.sa, salen);
+ strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path));
+ return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}
if (arg_remote_host[0] == '@') {
sa.un.sun_family = AF_UNIX;
sa.un.sun_path[0] = 0;
- strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2);
- sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
-
- salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1);
-
- return connection_start(c, &sa.sa, salen);
+ strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-1);
+ return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}
service = strrchr(arg_remote_host, ':');
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 9af25e22a4..639080bc66 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -1355,7 +1355,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
} else
id_cols = max_id_len;
- if (!arg_no_legend)
+ if (!arg_no_legend && c > 0)
printf("%-*s %-*s\n",
id_cols, "UNIT FILE",
state_cols, "STATE");
@@ -1422,8 +1422,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
n_units = hashmap_size(h);
- units = new(UnitFileList, n_units);
- if (!units && n_units > 0) {
+ units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
+ if (!units) {
unit_file_list_free(h);
return log_oom();
}
@@ -1519,10 +1519,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
- if (install_client_side()) {
+ if (install_client_side())
for (unit = units; unit < units + c; unit++)
free(unit->path);
- }
return 0;
}
@@ -1711,21 +1710,22 @@ static int list_dependencies_one(
const char *on;
(void) get_state_one_unit(bus, *c, &active_state);
+
switch (active_state) {
- case UNIT_ACTIVE:
- case UNIT_RELOADING:
- case UNIT_ACTIVATING:
- on = ansi_highlight_green();
- break;
-
- case UNIT_INACTIVE:
- case UNIT_DEACTIVATING:
- on = ansi_normal();
- break;
-
- default:
- on = ansi_highlight_red();
- break;
+ case UNIT_ACTIVE:
+ case UNIT_RELOADING:
+ case UNIT_ACTIVATING:
+ on = ansi_highlight_green();
+ break;
+
+ case UNIT_INACTIVE:
+ case UNIT_DEACTIVATING:
+ on = ansi_normal();
+ break;
+
+ default:
+ on = ansi_highlight_red();
+ break;
}
printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal());
@@ -2334,6 +2334,8 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
}
static void warn_unit_file_changed(const char *name) {
+ assert(name);
+
log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
ansi_highlight_red(),
ansi_normal(),
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 374ff8774e..20b8c2873f 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -84,28 +84,57 @@ enum {
typedef struct sd_dhcp_client sd_dhcp_client;
-typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event,
- void *userdata);
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb,
- void *userdata);
-
-int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
-int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
- const struct in_addr *last_address);
-int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
-int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
-int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
- size_t addr_len, uint16_t arp_type);
-int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
- const uint8_t *data, size_t data_len);
-int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
- uint16_t duid_type, uint8_t *duid, size_t duid_len);
-int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
- const uint8_t **data, size_t *data_len);
-int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
-int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
-int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);
-int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret);
+typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata);
+int sd_dhcp_client_set_callback(
+ sd_dhcp_client *client,
+ sd_dhcp_client_callback_t cb,
+ void *userdata);
+
+int sd_dhcp_client_set_request_option(
+ sd_dhcp_client *client,
+ uint8_t option);
+int sd_dhcp_client_set_request_address(
+ sd_dhcp_client *client,
+ const struct in_addr *last_address);
+int sd_dhcp_client_set_request_broadcast(
+ sd_dhcp_client *client,
+ int broadcast);
+int sd_dhcp_client_set_index(
+ sd_dhcp_client *client,
+ int interface_index);
+int sd_dhcp_client_set_mac(
+ sd_dhcp_client *client,
+ const uint8_t *addr,
+ size_t addr_len,
+ uint16_t arp_type);
+int sd_dhcp_client_set_client_id(
+ sd_dhcp_client *client,
+ uint8_t type,
+ const uint8_t *data,
+ size_t data_len);
+int sd_dhcp_client_set_iaid_duid(
+ sd_dhcp_client *client,
+ uint32_t iaid,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len);
+int sd_dhcp_client_get_client_id(
+ sd_dhcp_client *client,
+ uint8_t *type,
+ const uint8_t **data,
+ size_t *data_len);
+int sd_dhcp_client_set_mtu(
+ sd_dhcp_client *client,
+ uint32_t mtu);
+int sd_dhcp_client_set_hostname(
+ sd_dhcp_client *client,
+ const char *hostname);
+int sd_dhcp_client_set_vendor_class_identifier(
+ sd_dhcp_client *client,
+ const char *vci);
+int sd_dhcp_client_get_lease(
+ sd_dhcp_client *client,
+ sd_dhcp_lease **ret);
int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client);
@@ -115,7 +144,10 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
int sd_dhcp_client_new(sd_dhcp_client **ret);
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority);
+int sd_dhcp_client_attach_event(
+ sd_dhcp_client *client,
+ sd_event *event,
+ int64_t priority);
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index 4604cb6382..90f62eaca4 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -76,29 +76,52 @@ enum {
typedef struct sd_dhcp6_client sd_dhcp6_client;
-typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event,
- void *userdata);
-int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
- sd_dhcp6_client_callback_t cb, void *userdata);
-
-int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
-int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
-int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
- size_t addr_len, uint16_t arp_type);
-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type,
- uint8_t *duid, size_t duid_len);
-int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid);
-int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled);
-int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled);
-int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
- uint16_t option);
-
-int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
+typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata);
+int sd_dhcp6_client_set_callback(
+ sd_dhcp6_client *client,
+ sd_dhcp6_client_callback_t cb,
+ void *userdata);
+
+int sd_dhcp6_client_set_index(
+ sd_dhcp6_client *client,
+ int interface_index);
+int sd_dhcp6_client_set_local_address(
+ sd_dhcp6_client *client,
+ const struct in6_addr *local_address);
+int sd_dhcp6_client_set_mac(
+ sd_dhcp6_client *client,
+ const uint8_t *addr,
+ size_t addr_len,
+ uint16_t arp_type);
+int sd_dhcp6_client_set_duid(
+ sd_dhcp6_client *client,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len);
+int sd_dhcp6_client_set_iaid(
+ sd_dhcp6_client *client,
+ uint32_t iaid);
+int sd_dhcp6_client_set_information_request(
+ sd_dhcp6_client *client,
+ int enabled);
+int sd_dhcp6_client_get_information_request(
+ sd_dhcp6_client *client,
+ int *enabled);
+int sd_dhcp6_client_set_request_option(
+ sd_dhcp6_client *client,
+ uint16_t option);
+
+int sd_dhcp6_client_get_lease(
+ sd_dhcp6_client *client,
+ sd_dhcp6_lease **ret);
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
-int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority);
+int sd_dhcp6_client_attach_event(
+ sd_dhcp6_client *client,
+ sd_event *event,
+ int64_t priority);
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index af7a797567..3ae110c080 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -137,8 +137,10 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags);
+int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table);
int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family);
int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol);
int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope);
int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
index 4680b0336d..4b9a74fca4 100644
--- a/src/test/test-install-root.c
+++ b/src/test/test-install-root.c
@@ -681,6 +681,53 @@ static void test_revert(const char *root) {
changes = NULL; n_changes = 0;
}
+static void test_preset_order(const char *root) {
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+ const char *p;
+ UnitFileState state;
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT);
+
+ p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service");
+ assert_se(write_string_file(p,
+ "[Install]\n"
+ "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ p = strjoina(root, "/usr/lib/systemd/system/prefix-2.service");
+ assert_se(write_string_file(p,
+ "[Install]\n"
+ "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
+ assert_se(write_string_file(p,
+ "enable prefix-1.service\n"
+ "disable prefix-*.service\n"
+ "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+ assert_se(n_changes == 1);
+ assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service"));
+ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/prefix-1.service");
+ assert_se(streq(changes[0].path, p));
+ unit_file_changes_free(changes, n_changes);
+ changes = NULL; n_changes = 0;
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+ assert_se(n_changes == 0);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+}
+
int main(int argc, char *argv[]) {
char root[] = "/tmp/rootXXXXXX";
const char *p;
@@ -709,6 +756,7 @@ int main(int argc, char *argv[]) {
test_template_enable(root);
test_indirect(root);
test_preset_and_list(root);
+ test_preset_order(root);
test_revert(root);
assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 33ff3755bc..9e01f3afd4 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -343,6 +343,21 @@ static void test_sockaddr_equal(void) {
assert_se(!sockaddr_equal(&b, &c));
}
+static void test_sockaddr_un_len(void) {
+ static const struct sockaddr_un fs = {
+ .sun_family = AF_UNIX,
+ .sun_path = "/foo/bar/waldo",
+ };
+
+ static const struct sockaddr_un abstract = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0foobar",
+ };
+
+ assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path));
+ assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1));
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
@@ -363,5 +378,7 @@ int main(int argc, char *argv[]) {
test_sockaddr_equal();
+ test_sockaddr_un_len();
+
return 0;
}
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index c7ded451a2..ee879c7b89 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -65,8 +65,8 @@ static int ask_password_plymouth(
const char *flag_file,
char ***ret) {
+ static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_close_ int fd = -1, notify = -1;
- union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
@@ -94,7 +94,7 @@ static int ask_password_plymouth(
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
@@ -269,8 +269,7 @@ static int send_passwords(const char *socket_name, char **passwords) {
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa,
- offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
+ r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = log_debug_errno(errno, "sendto(): %m");
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 962de22f43..f68a09d7a8 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -105,7 +105,7 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
uctrl->saddr.un.sun_family = AF_LOCAL;
strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), "/run/udev/control");
- uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.un.sun_path);
+ uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
return uctrl;
}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 475856db6f..26fa52cf6c 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -329,8 +329,8 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
enum token_type type = token->type;
enum operation_type op = token->key.op;
enum string_glob_type glob = token->key.glob;
- const char *value = str(rules, token->key.value_off);
- const char *attr = &rules->buf[token->key.attr_off];
+ const char *value = rules_str(rules, token->key.value_off);
+ const char *attr = &rules->strbuf->buf[token->key.attr_off];
switch (type) {
case TK_RULE:
@@ -340,9 +340,9 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token);
log_debug("* RULE %s:%u, token: %u, count: %u, label: '%s'",
- &rules->buf[token->rule.filename_off], token->rule.filename_line,
+ &rules->strbuf->buf[token->rule.filename_off], token->rule.filename_line,
idx, token->rule.token_count,
- &rules->buf[token->rule.label_off]);
+ &rules->strbuf->buf[token->rule.label_off]);
break;
}
case TK_M_ACTION:
@@ -439,11 +439,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
static void dump_rules(struct udev_rules *rules) {
unsigned int i;
- log_debug("dumping %u (%zu bytes) tokens, %u (%zu bytes) strings",
+ log_debug("dumping %u (%zu bytes) tokens, %zu (%zu bytes) strings",
rules->token_cur,
rules->token_cur * sizeof(struct token),
- rules->buf_count,
- rules->buf_cur);
+ rules->strbuf->nodes_count,
+ rules->strbuf->len);
for (i = 0; i < rules->token_cur; i++)
dump_token(rules, &rules->tokens[i]);
}
diff --git a/test/TEST-06-SELINUX/Makefile b/test/TEST-06-SELINUX/Makefile
index 5e89a29eff..e9f93b1104 100644..120000
--- a/test/TEST-06-SELINUX/Makefile
+++ b/test/TEST-06-SELINUX/Makefile
@@ -1,10 +1 @@
-all:
- @make -s --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all
-setup:
- @make --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup
-clean:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean
-run:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-08-ISSUE-2730/Makefile b/test/TEST-08-ISSUE-2730/Makefile
index 5e89a29eff..e9f93b1104 100644..120000
--- a/test/TEST-08-ISSUE-2730/Makefile
+++ b/test/TEST-08-ISSUE-2730/Makefile
@@ -1,10 +1 @@
-all:
- @make -s --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all
-setup:
- @make --no-print-directory -C ../.. all
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup
-clean:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean
-run:
- @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-10-ISSUE-2467/Makefile b/test/TEST-10-ISSUE-2467/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-10-ISSUE-2467/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh
new file mode 100755
index 0000000000..a652b0d812
--- /dev/null
+++ b/test/TEST-10-ISSUE-2467/test.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2467"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ run_qemu || return 1
+ check_result_qemu || return 1
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install nc true rm
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo a | nc -U /run/test.ctl; >/testok'
+TimeoutStartSec=10s
+EOF
+
+ cat >$initdir/etc/systemd/system/test.socket <<'EOF'
+[Socket]
+ListenStream=/run/test.ctl
+EOF
+
+ cat > $initdir/etc/systemd/system/test.service <<'EOF'
+[Unit]
+Requires=test.socket
+ConditionPathExistsGlob=/tmp/nonexistent
+
+[Service]
+ExecStart=/bin/true
+EOF
+
+ setup_testsuite
+ ) || return 1
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-11-ISSUE-3166/Makefile b/test/TEST-11-ISSUE-3166/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-11-ISSUE-3166/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-11-ISSUE-3166/test.sh b/test/TEST-11-ISSUE-3166/test.sh
new file mode 100755
index 0000000000..7913537e9b
--- /dev/null
+++ b/test/TEST-11-ISSUE-3166/test.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3166"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ run_qemu || return 1
+ check_result_qemu || return 1
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install false touch
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-fail-on-restart.sh
+Type=oneshot
+EOF
+
+ cat >$initdir/etc/systemd/system/fail-on-restart.service <<EOF
+[Unit]
+Description=Fail on restart
+
+[Service]
+Type=simple
+ExecStart=/bin/false
+Restart=always
+EOF
+
+
+ cat >$initdir/test-fail-on-restart.sh <<'EOF'
+#!/bin/bash -x
+
+systemctl start fail-on-restart.service
+active_state=$(systemctl show --property ActiveState fail-on-restart.service)
+while [[ "$active_state" == "ActiveState=activating" || "$active_state" == "ActiveState=active" ]]; do
+ sleep 1
+ active_state=$(systemctl show --property ActiveState fail-on-restart.service)
+done
+systemctl is-failed fail-on-restart.service || exit 1
+touch /testok
+EOF
+
+ chmod 0755 $initdir/test-fail-on-restart.sh
+ setup_testsuite
+ ) || return 1
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-12-ISSUE-3171/Makefile b/test/TEST-12-ISSUE-3171/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-12-ISSUE-3171/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-12-ISSUE-3171/test.sh b/test/TEST-12-ISSUE-3171/test.sh
new file mode 100755
index 0000000000..925dcad9ea
--- /dev/null
+++ b/test/TEST-12-ISSUE-3171/test.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3171"
+
+. $TEST_BASE_DIR/test-functions
+
+test_run() {
+ run_nspawn || return 1
+ check_result_nspawn || return 1
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install cat mv stat nc
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-socket-group.sh
+Type=oneshot
+EOF
+
+
+ cat >$initdir/test-socket-group.sh <<'EOF'
+#!/bin/bash
+set -x
+set -e
+set -o pipefail
+
+U=/run/systemd/system/test.socket
+cat <<'EOL' >$U
+[Unit]
+Description=Test socket
+[Socket]
+Accept=yes
+ListenStream=/run/test.socket
+SocketGroup=adm
+SocketMode=0660
+EOL
+
+cat <<'EOL' > /run/systemd/system/test@.service
+[Unit]
+Description=Test service
+[Service]
+StandardInput=socket
+ExecStart=/bin/sh -x -c cat
+EOL
+
+systemctl start test.socket
+systemctl is-active test.socket
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+echo A | nc -U /run/test.socket
+
+mv $U ${U}.disabled
+systemctl daemon-reload
+systemctl is-active test.socket
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+echo B | nc -U /run/test.socket && exit 1
+
+mv ${U}.disabled $U
+systemctl daemon-reload
+systemctl is-active test.socket
+echo C | nc -U /run/test.socket && exit 1
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+
+systemctl restart test.socket
+systemctl is-active test.socket
+echo D | nc -U /run/test.socket
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+
+
+touch /testok
+EOF
+
+ chmod 0755 $initdir/test-socket-group.sh
+ setup_testsuite
+ ) || return 1
+
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4
index 276bc6b1ba..2cd58e9121 100644
--- a/tmpfiles.d/systemd.conf.m4
+++ b/tmpfiles.d/systemd.conf.m4
@@ -26,32 +26,48 @@ d /run/log 0755 root root -
z /run/log/journal 2755 root systemd-journal - -
Z /run/log/journal/%m ~2750 root systemd-journal - -
-m4_ifdef(`HAVE_ACL',
+m4_ifdef(`HAVE_ACL',`m4_dnl
+m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /run/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
-A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+a+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
+a+ /run/log/journal/%m/*.journal* - - - - group:adm:r--,group:wheel:r--
'',``
a+ /run/log/journal/%m - - - - d:group:adm:r-x
-A+ /run/log/journal/%m - - - - group:adm:r-x
-''))m4_dnl
+a+ /run/log/journal/%m - - - - group:adm:r-x
+a+ /run/log/journal/%m/*.journal* - - - - group:adm:r--
+'')',`m4_dnl
+m4_ifdef(`ENABLE_WHEEL_GROUP',``
+a+ /run/log/journal/%m - - - - d:group:wheel:r-x
+a+ /run/log/journal/%m - - - - group:wheel:r-x
+a+ /run/log/journal/%m/*.journal* - - - - group:wheel:r--
+'')')')m4_dnl
z /var/log/journal 2755 root systemd-journal - -
z /var/log/journal/%m 2755 root systemd-journal - -
z /var/log/journal/%m/system.journal 0640 root systemd-journal - -
-m4_ifdef(`HAVE_ACL',
+m4_ifdef(`HAVE_ACL',`m4_dnl
+m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
m4_ifdef(`ENABLE_WHEEL_GROUP',``
a+ /var/log/journal - - - - d:group:adm:r-x,d:group:wheel:r-x
a+ /var/log/journal - - - - group:adm:r-x,group:wheel:r-x
a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r--
-'',``
+'', ``
a+ /var/log/journal - - - - d:group:adm:r-x
a+ /var/log/journal - - - - group:adm:r-x
a+ /var/log/journal/%m - - - - d:group:adm:r-x
a+ /var/log/journal/%m - - - - group:adm:r-x
a+ /var/log/journal/%m/system.journal - - - - group:adm:r--
-''))m4_dnl
+'')',`m4_dnl
+m4_ifdef(`ENABLE_WHEEL_GROUP',``
+a+ /var/log/journal - - - - d:group:wheel:r-x
+a+ /var/log/journal - - - - group:wheel:r-x
+a+ /var/log/journal/%m - - - - d:group:wheel:r-x
+a+ /var/log/journal/%m - - - - group:wheel:r-x
+a+ /var/log/journal/%m/system.journal - - - - group:wheel:r--
+'')')')m4_dnl
d /var/lib/systemd 0755 root root -
d /var/lib/systemd/coredump 0755 root root 3d