]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #20419 from keszybz/setenv-no-value
authorLennart Poettering <lennart@poettering.net>
Wed, 11 Aug 2021 15:47:45 +0000 (17:47 +0200)
committerGitHub <noreply@github.com>
Wed, 11 Aug 2021 15:47:45 +0000 (17:47 +0200)
Allow --setenv=FOO in various programs

97 files changed:
TODO
catalog/systemd.catalog.in
hwdb.d/60-autosuspend-fingerprint-reader.hwdb
hwdb.d/60-evdev.hwdb
hwdb.d/80-ieee1394-unit-function.hwdb
man/logind.conf.xml
man/systemd-analyze.xml
man/systemd-sysusers.xml
man/systemd-timesyncd.service.xml
man/systemd.special.xml
man/timesyncd.conf.xml
po/zh_TW.po
shell-completion/bash/systemd-analyze
shell-completion/zsh/_systemd-analyze
src/analyze/analyze-condition.c
src/analyze/analyze-verify.c
src/analyze/analyze-verify.h
src/analyze/analyze.c
src/analyze/test-verify.c
src/basic/alloc-util.h
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/list.h
src/basic/memory-util.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/special.h
src/boot/bootctl.c
src/boot/efi/random-seed.c
src/boot/efi/util.c
src/core/device.c
src/core/execute.c
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/swap.c
src/core/unit.c
src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
src/fstab-generator/fstab-generator.c
src/import/pull-common.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd/sd-bus/bus-socket.c
src/login/logind-action.c
src/login/logind-action.h
src/login/logind-dbus.c
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp4.c
src/network/networkd-dhcp4.h
src/network/networkd-dhcp6.c
src/network/networkd-dhcp6.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-lldp-rx.c
src/network/networkd-lldp-rx.h
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-ndisc.c
src/network/networkd-ndisc.h
src/network/networkd-queue.c
src/network/networkd-queue.h
src/network/networkd-radv.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-stub.c
src/shared/utmp-wtmp.c
src/systemd/sd-messages.h
src/test/test-bpf-firewall.c
src/test/test-bpf-foreign-programs.c
src/test/test-cgroup-mask.c
src/test/test-cgroup-unit-default.c
src/test/test-engine.c
src/test/test-execute.c
src/test/test-load-fragment.c
src/test/test-path-util.c
src/test/test-path.c
src/test/test-sched-prio.c
src/test/test-socket-bind.c
src/test/test-watch-pid.c
src/timesync/timesyncd-gperf.gperf
src/timesync/timesyncd-manager.c
src/timesync/timesyncd-manager.h
src/timesync/timesyncd.c
src/timesync/timesyncd.conf.in
src/udev/udev-ctrl.c
src/udev/udev-ctrl.h
src/udev/udev-rules.c
src/udev/udevadm-control.c
src/udev/udevadm-settle.c
src/udev/udevadm-trigger.c
src/udev/udevd.c
test/TEST-13-NSPAWN-SMOKE/test.sh
test/test-functions
test/test-network/systemd-networkd-tests.py
test/units/testsuite-10.service
units/factory-reset.target [new file with mode: 0644]
units/meson.build
units/systemd-tmpfiles-clean.service
units/systemd-tmpfiles-setup.service

diff --git a/TODO b/TODO
index 16a91fa02366eb5ff2f4d016a5c3d9dd624dfcb8..de27269d84b27de073c7c93ad49b937a5a967db1 100644 (file)
--- a/TODO
+++ b/TODO
@@ -83,6 +83,15 @@ Janitorial Clean-ups:
 
 Features:
 
+* tpm2: figure out if we need to do anything for TPM2 parameter encryption? And
+  if so, what precisely?
+
+* insert pkcs7 signature for verity gpt
+
+* when mounting disk images: if IMAGE_ID/IMAGE_VERSION is set in os-release
+  data in the image, make sure the image filename actually matches this, so
+  that images cannot be misused.
+
 * use credentials logic/TPM2 logic to store homed signing key
 
 * New udev block device symlink names:
index 3e08f564a64069200babc5fe76e18bb711bb7c8a..a5d7dc6f78d6636a36d94efc22af8f2db8f8a3f4 100644 (file)
@@ -188,6 +188,15 @@ Support: %SUPPORT_URL%
 System shutdown has been initiated. The shutdown has now begun and
 all system services are terminated and all file systems unmounted.
 
+-- c14aaf76ec284a5fa1f105f88dfb061c
+Subject: System factory reset initiated
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+System factory reset has been initiated. The precise operation this
+executes is implementation-defined, but typically has the effect of
+reverting the system's state and configuration to vendor defaults.
+
 -- 7d4958e842da4a758f6c1cdc7b36dcc5
 Subject: A start job for unit @UNIT@ has begun execution
 Defined-By: systemd
index 7566798e2bbf375a244819be73eb1030f79316be..c1485e1256c74beeb95ad50aaca619298fdef790 100644 (file)
@@ -68,6 +68,11 @@ usb:v08FFp5731*
 usb:v5501p08FF*
  ID_AUTOSUSPEND=1
 
+# Supported by libfprint driver egis0570
+usb:v1C7Ap0570*
+usb:v1C7Ap0571*
+ ID_AUTOSUSPEND=1
+
 # Supported by libfprint driver elan
 usb:v04F3p0903*
 usb:v04F3p0907*
@@ -127,6 +132,11 @@ usb:v04F3p0C42*
 usb:v04F3p0C4D*
 usb:v04F3p0C4F*
 usb:v04F3p0C63*
+usb:v04F3p0C6E*
+ ID_AUTOSUSPEND=1
+
+# Supported by libfprint driver elanmoc
+usb:v04F3p0C7E*
  ID_AUTOSUSPEND=1
 
 # Supported by libfprint driver etes603
@@ -264,7 +274,6 @@ usb:v147Ep1002*
 usb:v1491p0088*
 usb:v16D1p1027*
 usb:v1C7Ap0300*
-usb:v1C7Ap0570*
 usb:v1C7Ap0575*
 usb:v27C6p5042*
 usb:v27C6p5110*
index 96c5da1104c6255b00d19d3302bc9ab0398c6d80..bd463a4215494bc5775fd58fc10248a9b6178f96 100644 (file)
@@ -567,9 +567,11 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoU41-70:*
  EVDEV_ABS_35=117:3958:36
  EVDEV_ABS_36=104:1960:26
 
-# Lenovo Thinkpad T490 and T14 Gen1
+# Lenovo Thinkpad T490 and T14/P14s Gen1/2
 evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:*
 evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen1:*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen1:*
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadP14sGen2a:*
  EVDEV_ABS_00=::44
  EVDEV_ABS_01=::52
  EVDEV_ABS_35=::44
index aa007112112d2b0c4a5adef0e2650d8c9ada9411..2f879da34686b210457b32812b0759ce18e3cf79 100644 (file)
@@ -112,14 +112,6 @@ ieee1394:ven*sp0000A02Dver00000110
 # BridgeCo. Enhancement BreakOut Box (BeBoB) for DM1000, DM1100, and DM1500 ASICs.
 #
 
-# Match to eAR Master One, Eroica, Figaro, and Ciaccona.
-ieee1394:node:ven0x000aacmo0x000002units0x00a02d:0x010001
-ieee1394:ven00000AACmo00000002sp0000A02Dver00010001
- ID_VENDOR_FROM_DATABASE=Acoustic Reality
- ID_MODEL_FROM_DATABASE=eAR FireWire Audio
- IEEE1394_UNIT_FUNCTION_AUDIO=1
- IEEE1394_UNIT_FUNCTION_VIDEO=0
-
 ieee1394:node:ven0x0003dbmo0x01eeeeunits0x00a02d:0x010001
 ieee1394:ven000003DBmo0001EEEEsp0000A02Dver00010001
  ID_VENDOR_FROM_DATABASE=Apogee Electronics
@@ -322,7 +314,7 @@ ieee1394:ven00000FF2mo00010065sp0000A02Dver00010001
  IEEE1394_UNIT_FUNCTION_AUDIO=1
  IEEE1394_UNIT_FUNCTION_VIDEO=0
 
-# An extension card for Mackie d.2.
+# An extension card for Mackie d.2. Mackie d.2 Pro is preinstalled model.
 ieee1394:node:ven0x000ff2mo0x010067units0x00a02d:0x010001
 ieee1394:ven00000FF2mo00010067sp0000A02Dver00010001
  ID_VENDOR_FROM_DATABASE=Loud Technologies
@@ -330,8 +322,41 @@ ieee1394:ven00000FF2mo00010067sp0000A02Dver00010001
  IEEE1394_UNIT_FUNCTION_AUDIO=1
  IEEE1394_UNIT_FUNCTION_VIDEO=0
 
-# Match to FireFly 202, 302, 808, and 808 Universal.
-# Match to HelixBoard 12 mk II, 18 mk II, 24 mk II, 12 Universal, 18 Universal, and 24 Universal.
+ieee1394:node:ven0x001496mo0x050000units0x00a02d:0x010001
+ieee1394:ven00001496mo00050000sp0000A02Dver00010001
+ ID_VENDOR_FROM_DATABASE=Phonic
+ ID_MODEL_FROM_DATABASE=Helixboard 12 FireWire MkII
+ IEEE1394_UNIT_FUNCTION_MIDI=1
+ IEEE1394_UNIT_FUNCTION_AUDIO=1
+ IEEE1394_UNIT_FUNCTION_VIDEO=0
+
+ieee1394:node:ven0x001496mo0x060000units0x00a02d:0x010001
+ieee1394:ven00001496mo00060000sp0000A02Dver00010001
+ ID_VENDOR_FROM_DATABASE=Phonic
+ ID_MODEL_FROM_DATABASE=Helixboard 18 FireWire MkII
+ IEEE1394_UNIT_FUNCTION_MIDI=1
+ IEEE1394_UNIT_FUNCTION_AUDIO=1
+ IEEE1394_UNIT_FUNCTION_VIDEO=0
+
+ieee1394:node:ven0x001496mo0x070000units0x00a02d:0x010001
+ieee1394:ven00001496mo00070000sp0000A02Dver00010001
+ ID_VENDOR_FROM_DATABASE=Phonic
+ ID_MODEL_FROM_DATABASE=Helixboard 24 FireWire MkII
+ IEEE1394_UNIT_FUNCTION_MIDI=1
+ IEEE1394_UNIT_FUNCTION_AUDIO=1
+ IEEE1394_UNIT_FUNCTION_VIDEO=0
+
+ieee1394:node:ven0x001496mo0x080000units0x00a02d:0x010001
+ieee1394:ven00001496mo00080000sp0000A02Dver00010001
+ ID_VENDOR_FROM_DATABASE=Phonic
+ ID_MODEL_FROM_DATABASE=Firefly 808 FireWire
+ IEEE1394_UNIT_FUNCTION_MIDI=1
+ IEEE1394_UNIT_FUNCTION_AUDIO=1
+ IEEE1394_UNIT_FUNCTION_VIDEO=0
+
+# Match to FireFly 202, 302, 808 Universal.
+# Match to HelixBoard 12 FireWire, 18 FireWire, 24 FireWire.
+# Match to HelixBoard 12 Universal, 18 Universal, and 24 Universal.
 ieee1394:node:ven0x001496mo0x000000units0x00a02d:0x010001
 ieee1394:ven00001496mo00000000sp0000A02Dver00010001
  ID_VENDOR_FROM_DATABASE=Phonic
@@ -386,6 +411,15 @@ ieee1394:ven00010065mo00010067sp0000A02Dver00010001
  IEEE1394_UNIT_FUNCTION_AUDIO=1
  IEEE1394_UNIT_FUNCTION_VIDEO=0
 
+# Match to TerraTec Aureon 7.1 FireWire.
+# Match to eAR Master One, Eroica, Figaro, and Ciaccona. OEM by TerraTec perhaps.
+ieee1394:node:ven0x000aacmo0x000002units0x00a02d:0x010001
+ieee1394:ven00000AACmo00000002sp0000A02Dver00010001
+ ID_VENDOR_FROM_DATABASE=TerraTec
+ ID_MODEL_FROM_DATABASE=Aureon 7.1 FireWire
+ IEEE1394_UNIT_FUNCTION_AUDIO=1
+ IEEE1394_UNIT_FUNCTION_VIDEO=0
+
 ieee1394:node:ven0x000aacmo0x000003units0x00a02d:0x010001
 ieee1394:ven00000AACmo00000003sp0000A02Dver00010001
  ID_VENDOR_FROM_DATABASE=TerraTec Electronic
@@ -545,6 +579,7 @@ ieee1394:ven00000FF2mo00081216sp0000A02Dver00010001
  IEEE1394_UNIT_FUNCTION_AUDIO=1
  IEEE1394_UNIT_FUNCTION_VIDEO=0
 
+# Match to former model of Onyx 1640i.
 ieee1394:node:ven0x000ff2mo0x001640units0x00a02d:0x010001
 ieee1394:ven00000FF2mo00001640sp0000A02Dver00010001
  ID_VENDOR_FROM_DATABASE=Loud Technologies
@@ -707,7 +742,7 @@ ieee1394:ven00000FF2mo00000007sp00000FF2ver00000001
  ID_MODEL_FROM_DATABASE=Mackie Onyx Blackbird
  IEEE1394_UNIT_FUNCTION_AUDIO=1
 
-# Match to Onyx 1640i, and latter models of Onyx 820i, 1220i, and 1620i.
+# Match to latter models of Onyx 820i, 1220i, 1620i, and 1640i.
 ieee1394:node:ven0x000ff2mo0x000006units0x000ff2:0x000001
 ieee1394:ven00000FF2mo00000006sp00000FF2ver00000001
  ID_VENDOR_FROM_DATABASE=Loud Technologies
index 5dc24a3f05306a2a8cb74af604d21255f74ede3a..3045c1b9ba675970e8341d9e86eac4415474d94a 100644 (file)
         <literal>suspend</literal>,
         <literal>hibernate</literal>,
         <literal>hybrid-sleep</literal>,
-        <literal>suspend-then-hibernate</literal>, and
-        <literal>lock</literal>.
+        <literal>suspend-then-hibernate</literal>,
+        <literal>lock</literal>, and
+        <literal>factory-reset</literal>.
         If <literal>ignore</literal>, logind will never handle these
         keys. If <literal>lock</literal>, all running sessions will be
         screen-locked; otherwise, the specified action will be taken
index 4da066e05c26854a032e0b0e5b0fcccc4a9f2380..dc93ac4e72e6fabcd4deebc4e9dd366928035c7a 100644 (file)
@@ -747,8 +747,15 @@ Service b@0.service not loaded, b.socket cannot be started.
       <varlistentry>
         <term><option>--root=<replaceable>PATH</replaceable></option></term>
 
-        <listitem><para>With <command>cat-files</command>, show config files underneath
-        the specified root path <replaceable>PATH</replaceable>.</para></listitem>
+        <listitem><para>With <command>cat-files</command> and <command>verify</command>,
+        operate on files underneath the specified root path <replaceable>PATH</replaceable>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--image=<replaceable>PATH</replaceable></option></term>
+
+        <listitem><para>With <command>cat-files</command> and <command>verify</command>,
+        operate on files inside the specified image path <replaceable>PATH</replaceable>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index b4500d1448a9c1660241eab6c79c24aab5de4429..e0a89b071221d8af36b630172378fbe97a0960a1 100644 (file)
     for the first time it is possible to configure the root user's password to be <literal>systemd</literal>
     like this:</para>
 
-    <para><programlisting># systemd-nspawn --image=… --set-credential=password.hashed-password.root:'$y$j9T$yAuRJu1o5HioZAGDYPU5d.$F64ni6J2y2nNQve90M/p0ZP0ECP/qqzipNyaY9fjGpC' …</programlisting></para>
+    <para><programlisting># systemd-nspawn --image=… --set-credential=passwd.hashed-password.root:'$y$j9T$yAuRJu1o5HioZAGDYPU5d.$F64ni6J2y2nNQve90M/p0ZP0ECP/qqzipNyaY9fjGpC' …</programlisting></para>
 
     <para>Note again that the data specified in these credentials is consulted only when creating an account
     for the first time, it may not be used for changing the password or shell of an account that already
index 9ab4af9763bef47b5d48aa443ec96b2a3d7278f9..34e0a674720078d1f5cf132573adee8e34008bda 100644 (file)
         <term><filename>/var/lib/systemd/timesync/clock</filename></term>
 
         <listitem>
-          <para>The modification time ("mtime") of this file indicates the timestamp of the last successful
-          synchronization (or at least the systemd build date, in case synchronization was not possible). It
-          is used to ensure that the system clock remains roughly monotonic across reboots, in case no local
-          RTC is available.</para>
+          <para>The modification time ("mtime") of this file is updated on each successful NTP synchronization
+          or after each <varname>SaveIntervalSec=</varname> time interval, as specified in
+          <citerefentry><refentrytitle>timesyncd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+          At the minimum, it will be set to the systemd build date. It is used to ensure that the system clock
+          remains roughly monotonic across reboots, in case no local RTC is available.</para>
         </listitem>
       </varlistentry>
 
index b09c4e9fa2ee48fa59f3a36057934574b7f64967..8755b523ae2b7204c1a4bacb650799d41453bffc 100644 (file)
@@ -33,6 +33,7 @@
     <filename>default.target</filename>,
     <filename>emergency.target</filename>,
     <filename>exit.target</filename>,
+    <filename>factory-reset.target</filename>,
     <filename>final.target</filename>,
     <filename>first-boot-complete.target</filename>,
     <filename>getty.target</filename>,
             shutdown when the service manager starts to exit.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><filename>factory-reset.target</filename></term>
+          <listitem>
+            <para>A special target to trigger a factory reset.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><filename>final.target</filename></term>
           <listitem>
index 3fd11cea04c7d2337bcfa96d252cd90cf847bf52..07472cdb39b0d921104c35316b14c8614029136a 100644 (file)
         Defaults to 30 seconds and must not be smaller than 1 second.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>SaveIntervalSec=</varname></term>
+        <listitem><para>The interval at which the current time is periodically saved to disk, in the absence
+        of any recent synchronisation from an NTP server. This is especially useful for offline systems
+        with no local RTC, as it will guarantee that the system clock remains roughly monotonic across
+        reboots.</para>
+
+        <para>Takes a time interval value. The default unit is seconds, but other units may be specified, see
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        Defaults to 60 seconds.</para></listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index f47d9491325c4f070fea58b4414cab7dff1c3abe..4b297aa43da6e989660cc7df31212d5a90b7e2b0 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-08 17:48+0100\n"
-"PO-Revision-Date: 2019-10-23 19:19+0800\n"
+"PO-Revision-Date: 2021-08-10 11:36+0800\n"
 "Last-Translator: pan93412 <pan93412@gmail.com>\n"
 "Language-Team: Chinese <chinese-l10n@googlegroups.com>\n"
 "Language: zh_TW\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Lokalize 19.08.2\n"
+"X-Generator: Poedit 2.2.1\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -63,67 +63,53 @@ msgstr "重新載入 systemd 狀態需要驗證。"
 
 #: src/home/org.freedesktop.home1.policy:13
 msgid "Create a home area"
-msgstr ""
+msgstr "創建一個家區域"
 
 #: src/home/org.freedesktop.home1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to set NTP servers."
 msgid "Authentication is required to create a user's home area."
-msgstr "設定 NTP 伺服器需要身份驗證。"
+msgstr "創建用戶家區域需要身份驗證。"
 
 #: src/home/org.freedesktop.home1.policy:23
 msgid "Remove a home area"
-msgstr ""
+msgstr "移除一個家區域"
 
 #: src/home/org.freedesktop.home1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to set NTP servers."
 msgid "Authentication is required to remove a user's home area."
-msgstr "設定 NTP 伺服器需要身份驗證。"
+msgstr "移除用戶家區域需要身份驗證。"
 
 #: src/home/org.freedesktop.home1.policy:33
 msgid "Check credentials of a home area"
-msgstr ""
+msgstr "檢查家區域憑證"
 
 #: src/home/org.freedesktop.home1.policy:34
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to attach or detach a portable service image."
 msgid ""
 "Authentication is required to check credentials against a user's home area."
-msgstr "連結或取消連結可攜式服務映像需要身份驗證。"
+msgstr "根據用戶家區域檢查憑證需要認證。"
 
 #: src/home/org.freedesktop.home1.policy:43
 msgid "Update a home area"
-msgstr ""
+msgstr "更新一個家區域"
 
 #: src/home/org.freedesktop.home1.policy:44
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
 msgid "Authentication is required to update a user's home area."
-msgstr "將設備連接到座位需要驗證。"
+msgstr "更新用戶家區域需要認證。"
 
 #: src/home/org.freedesktop.home1.policy:53
 msgid "Resize a home area"
-msgstr ""
+msgstr "調整家區域大小"
 
 #: src/home/org.freedesktop.home1.policy:54
-#, fuzzy
-#| msgid "Authentication is required to set NTP servers."
 msgid "Authentication is required to resize a user's home area."
-msgstr "設å®\9a NTP ä¼ºæ\9c\8då\99¨é\9c\80è¦\81身份é©\97證。"
+msgstr "調æ\95´å®¶å\8d\80å\9f\9f大å°\8fé\9c\80è¦\81èª\8d證。"
 
 #: src/home/org.freedesktop.home1.policy:63
 msgid "Change password of a home area"
-msgstr ""
+msgstr "更改家區域的密碼"
 
 #: src/home/org.freedesktop.home1.policy:64
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
 msgid ""
 "Authentication is required to change the password of a user's home area."
-msgstr "管理活躍的工作階段、使用者與座位需要驗證。"
+msgstr "更改家區域密碼需要認證。"
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
 msgid "Set hostname"
@@ -283,20 +269,14 @@ msgid ""
 msgstr "要讓應用程式阻止系統處理上蓋開關需要驗證。"
 
 #: src/login/org.freedesktop.login1.policy:117
-#, fuzzy
-#| msgid "Allow applications to inhibit system handling of the power key"
 msgid "Allow applications to inhibit system handling of the reboot key"
-msgstr "å\85\81許æ\87\89ç\94¨ç¨\8bå¼\8fé\98»æ­¢ç³»çµ±è\99\95ç\90\86é\9b»æº\90鍵"
+msgstr "å\85\81許æ\87\89ç\94¨ç¨\8bå¼\8fé\98»æ­¢ç³»çµ±è\99\95ç\90\86é\87\8då\95\93鍵"
 
 #: src/login/org.freedesktop.login1.policy:118
-#, fuzzy
-#| msgid ""
-#| "Authentication is required for an application to inhibit system handling "
-#| "of the power key."
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the reboot key."
-msgstr "è¦\81è®\93æ\87\89ç\94¨ç¨\8bå¼\8fé\98»æ­¢ç³»çµ±è\99\95ç\90\86é\9b»æº\90鍵需要驗證。"
+msgstr "è¦\81è®\93æ\87\89ç\94¨ç¨\8bå¼\8fé\98»æ­¢ç³»çµ±è\99\95ç\90\86é\87\8då\95\93鍵需要驗證。"
 
 #: src/login/org.freedesktop.login1.policy:128
 msgid "Allow non-logged-in user to run programs"
@@ -409,14 +389,10 @@ msgid "Halt the system while an application is inhibiting this"
 msgstr "在應用程式阻止時停止系統"
 
 #: src/login/org.freedesktop.login1.policy:258
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while an application "
-#| "is inhibiting this."
 msgid ""
 "Authentication is required to halt the system while an application is "
 "inhibiting this."
-msgstr "當應用程式阻止系統冬眠時將系統冬眠需要驗證。"
+msgstr "當應用程式阻止停止系統時需要驗證。"
 
 #: src/login/org.freedesktop.login1.policy:268
 msgid "Suspend the system"
@@ -538,13 +514,11 @@ msgstr "設定 wall 訊息需要身份驗證"
 
 #: src/login/org.freedesktop.login1.policy:406
 msgid "Change Session"
-msgstr ""
+msgstr "更改會話"
 
 #: src/login/org.freedesktop.login1.policy:407
-#, fuzzy
-#| msgid "Authentication is required to halt the system."
 msgid "Authentication is required to change the virtual terminal."
-msgstr "停止系統需要身份驗證。"
+msgstr "更改虛擬終端需要身份驗證。"
 
 #: src/machine/org.freedesktop.machine1.policy:22
 msgid "Log into a local container"
@@ -720,13 +694,11 @@ msgstr "重設 DNS 設定需要身份驗證。"
 
 #: src/network/org.freedesktop.network1.policy:143
 msgid "DHCP server sends force renew message"
-msgstr ""
+msgstr "DHCP 服務器發送強制更新訊息"
 
 #: src/network/org.freedesktop.network1.policy:144
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to send force renew message."
-msgstr "設定 wall 訊息需要身份驗證"
+msgstr "發送強制更新訊息需要身份驗證。"
 
 #: src/network/org.freedesktop.network1.policy:154
 msgid "Renew dynamic addresses"
@@ -737,26 +709,20 @@ msgid "Authentication is required to renew dynamic addresses."
 msgstr "重新產生動態位址需要身份驗證。"
 
 #: src/network/org.freedesktop.network1.policy:165
-#, fuzzy
-#| msgid "Revert NTP settings"
 msgid "Reload network settings"
-msgstr "é\82\84å\8e\9f NTP 設定"
+msgstr "é\87\8dæ\96°å\8a è¼\89網絡設定"
 
 #: src/network/org.freedesktop.network1.policy:166
-#, fuzzy
-#| msgid "Authentication is required to reset NTP settings."
 msgid "Authentication is required to reload network settings."
-msgstr "重設 NTP 設定需要身份驗證。"
+msgstr "重新加載網絡設定需要身份驗證。"
 
 #: src/network/org.freedesktop.network1.policy:176
 msgid "Reconfigure network interface"
-msgstr ""
+msgstr "重新配置網絡接口"
 
 #: src/network/org.freedesktop.network1.policy:177
-#, fuzzy
-#| msgid "Authentication is required to reboot the system."
 msgid "Authentication is required to reconfigure network interface."
-msgstr "重新啟動系統需要驗證。"
+msgstr "重新配置網絡接口需要驗證。"
 
 #: src/portable/org.freedesktop.portable1.policy:13
 msgid "Inspect a portable service image"
@@ -881,13 +847,9 @@ msgid ""
 msgstr "刪除與 '$(unit)' 相關的檔案及目錄需要身份驗證。"
 
 #: src/core/dbus-unit.c:757
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to send a UNIX signal to the processes of "
-#| "'$(unit)'."
 msgid ""
 "Authentication is required to freeze or thaw the processes of '$(unit)' unit."
-msgstr "å\82³é\80\81 UNIX ä¿¡è\99\9fè\87³「$(unit)」的程序需要身份驗證。"
+msgstr "å\87\8dçµ\90æ\88\96解å\87\8d「$(unit)」的程序需要身份驗證。"
 
 #~ msgid ""
 #~ "Authentication is required to halt the system while an application asked "
index 36fcf432ff91b92ed675862802cbeca0ee523feb..872518add0d3f6f72f94fbc70bad887ec22bfcc1 100644 (file)
@@ -125,7 +125,7 @@ _systemd_analyze() {
 
     elif __contains_word "$verb" ${VERBS[VERIFY]}; then
         if [[ $cur = -* ]]; then
-            comps='--help --version --system --user --global --man=no --generators=yes'
+            comps='--help --version --system --user --global --man=no --generators=yes --root --image'
         else
             comps=$( compgen -A file -- "$cur" )
             compopt -o filenames
index ce8e6162e810cfa9878b38c5f4595286e74b08be..88a09d84b9d5f2d2473647d554ae5e145c0db382 100644 (file)
@@ -87,6 +87,8 @@ _arguments \
     '--system[Operate on system systemd instance]' \
     '--user[Operate on user systemd instance]' \
     '--global[Show global user instance config]' \
+    '--root=[Add support for root argument]:PATH' \
+    '--image=[Add support for discrete images]:PATH' \
     '--no-pager[Do not pipe output into a pager]' \
     '--man=[Do (not) check for existence of man pages]:boolean:(1 0)' \
     '--order[When generating graph for dot, show only order]' \
index 241c188ed6d187a46198ebd2b56843af4fed99d3..09870b95ec497b1e28e34feb6dcad05eb7a45467 100644 (file)
@@ -83,7 +83,7 @@ int verify_conditions(char **lines, UnitFileScope scope) {
                 return log_error_errno(r, "Failed to initialize manager: %m");
 
         log_debug("Starting manager...");
-        r = manager_startup(m, NULL, NULL);
+        r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, /* root= */ NULL);
         if (r < 0)
                 return r;
 
index bb5bdf998a35cfcc32ce0a85188b9f5c17754aca..9ef6868367d28acabb3880e422beb86d2fcf1e0d 100644 (file)
@@ -115,7 +115,7 @@ static int verify_socket(Unit *u) {
         return 0;
 }
 
-int verify_executable(Unit *u, const ExecCommand *exec) {
+int verify_executable(Unit *u, const ExecCommand *exec, const char *root) {
         int r;
 
         if (!exec)
@@ -124,14 +124,14 @@ int verify_executable(Unit *u, const ExecCommand *exec) {
         if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
                 return 0;
 
-        r = find_executable_full(exec->path, false, NULL, NULL);
+        r = find_executable_full(exec->path, root, false, NULL, NULL);
         if (r < 0)
                 return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path);
 
         return 0;
 }
 
-static int verify_executables(Unit *u) {
+static int verify_executables(Unit *u, const char *root) {
         ExecCommand *exec;
         int r = 0, k;
         unsigned i;
@@ -141,20 +141,20 @@ static int verify_executables(Unit *u) {
         exec =  u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
                 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
                 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
-        k = verify_executable(u, exec);
+        k = verify_executable(u, exec, root);
         if (k < 0 && r == 0)
                 r = k;
 
         if (u->type == UNIT_SERVICE)
                 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
-                        k = verify_executable(u, SERVICE(u)->exec_command[i]);
+                        k = verify_executable(u, SERVICE(u)->exec_command[i], root);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
 
         if (u->type == UNIT_SOCKET)
                 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
-                        k = verify_executable(u, SOCKET(u)->exec_command[i]);
+                        k = verify_executable(u, SOCKET(u)->exec_command[i], root);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
@@ -189,7 +189,7 @@ static int verify_documentation(Unit *u, bool check_man) {
         return r;
 }
 
-static int verify_unit(Unit *u, bool check_man) {
+static int verify_unit(Unit *u, bool check_man, const char *root) {
         _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
         int r, k;
 
@@ -207,7 +207,7 @@ static int verify_unit(Unit *u, bool check_man) {
         if (k < 0 && r == 0)
                 r = k;
 
-        k = verify_executables(u);
+        k = verify_executables(u, root);
         if (k < 0 && r == 0)
                 r = k;
 
@@ -218,7 +218,7 @@ static int verify_unit(Unit *u, bool check_man) {
         return r;
 }
 
-int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators) {
+int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, const char *root) {
         const ManagerTestRunFlags flags =
                 MANAGER_TEST_RUN_MINIMAL |
                 MANAGER_TEST_RUN_ENV_GENERATORS |
@@ -246,7 +246,7 @@ int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run
 
         log_debug("Starting manager...");
 
-        r = manager_startup(m, NULL, NULL);
+        r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, root);
         if (r < 0)
                 return r;
 
@@ -278,7 +278,7 @@ int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run
         }
 
         for (i = 0; i < count; i++) {
-                k = verify_unit(units[i], check_man);
+                k = verify_unit(units[i], check_man, root);
                 if (k < 0 && r == 0)
                         r = k;
         }
index 43bfbcbc8c4eaa35bb8f6b04d3c7ae7f550ec42f..6b3d6a5ab5d6b85f8a1771292b4cb332916d0f8e 100644 (file)
@@ -6,5 +6,5 @@
 #include "execute.h"
 #include "path-lookup.h"
 
-int verify_executable(Unit *u, const ExecCommand *exec);
-int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators);
+int verify_executable(Unit *u, const ExecCommand *exec, const char *root);
+int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, const char *root);
index e7600934eaa6ba524574805087e053183ae16abb..8d637ff8de9e44be9f1a9c98b178bf634510372b 100644 (file)
@@ -34,6 +34,7 @@
 #include "locale-util.h"
 #include "log.h"
 #include "main-func.h"
+#include "mount-util.h"
 #include "nulstr-util.h"
 #include "pager.h"
 #include "parse-argument.h"
@@ -86,12 +87,15 @@ static const char *arg_host = NULL;
 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
 static bool arg_man = true;
 static bool arg_generators = false;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
+static char *arg_image = NULL;
 static unsigned arg_iterations = 1;
 static usec_t arg_base_time = USEC_INFINITY;
 
 STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
 
 typedef struct BootTimes {
         usec_t firmware_time;
@@ -2141,7 +2145,7 @@ static int do_condition(int argc, char *argv[], void *userdata) {
 }
 
 static int do_verify(int argc, char *argv[], void *userdata) {
-        return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators);
+        return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators, arg_root);
 }
 
 static int do_security(int argc, char *argv[], void *userdata) {
@@ -2231,6 +2235,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ORDER,
                 ARG_REQUIRE,
                 ARG_ROOT,
+                ARG_IMAGE,
                 ARG_SYSTEM,
                 ARG_USER,
                 ARG_GLOBAL,
@@ -2250,6 +2255,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "order",        no_argument,       NULL, ARG_ORDER            },
                 { "require",      no_argument,       NULL, ARG_REQUIRE          },
                 { "root",         required_argument, NULL, ARG_ROOT             },
+                { "image",        required_argument, NULL, ARG_IMAGE            },
                 { "system",       no_argument,       NULL, ARG_SYSTEM           },
                 { "user",         no_argument,       NULL, ARG_USER             },
                 { "global",       no_argument,       NULL, ARG_GLOBAL           },
@@ -2281,7 +2287,15 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case ARG_ROOT:
-                        arg_root = optarg;
+                        r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root);
+                        if (r < 0)
+                                return r;
+                        break;
+
+                case ARG_IMAGE:
+                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case ARG_SYSTEM:
@@ -2378,14 +2392,21 @@ static int parse_argv(int argc, char *argv[]) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Option --user is not supported for cat-config right now.");
 
-        if (arg_root && !streq_ptr(argv[optind], "cat-config"))
+        if ((arg_root || arg_image) && !STRPTR_IN_SET(argv[optind], "cat-config", "verify"))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Option --root is only supported for cat-config right now.");
+                                       "Options --root= and --image= are only supported for cat-config and verify right now.");
+
+        /* Having both an image and a root is not supported by the code */
+        if (arg_root && arg_image)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
 
         return 1; /* work to do */
 }
 
 static int run(int argc, char *argv[]) {
+        _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
+        _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
+        _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
 
         static const Verb verbs[] = {
                 { "help",              VERB_ANY, VERB_ANY, 0,            help                   },
@@ -2429,6 +2450,26 @@ static int run(int argc, char *argv[]) {
         if (r <= 0)
                 return r;
 
+        /* Open up and mount the image */
+        if (arg_image) {
+                assert(!arg_root);
+
+                r = mount_image_privately_interactively(
+                                arg_image,
+                                DISSECT_IMAGE_GENERIC_ROOT |
+                                DISSECT_IMAGE_RELAX_VAR_CHECK |
+                                DISSECT_IMAGE_READ_ONLY,
+                                &unlink_dir,
+                                &loop_device,
+                                &decrypted_image);
+                if (r < 0)
+                        return r;
+
+                arg_root = strdup(unlink_dir);
+                if (!arg_root)
+                        return log_oom();
+        }
+
         return dispatch_verb(argc, argv, verbs, NULL);
 }
 
index 12c32159e56e9c0cd937344357171a06f1d965ed..eaf5e0b39b41d15c16b39bd8228cbaf1a16a1012 100644 (file)
@@ -4,12 +4,12 @@
 
 static void test_verify_nonexistent(void) {
         /* Negative cases */
-        assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/non/existent"}) == 0);
-        assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/non/existent"}) < 0);
+        assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/non/existent"}, NULL) == 0);
+        assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/non/existent"}, NULL) < 0);
 
         /* Ordinary cases */
-        assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/bin/echo"}) == 0);
-        assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/bin/echo"}) == 0);
+        assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/bin/echo"}, NULL) == 0);
+        assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/bin/echo"}, NULL) == 0);
 }
 
 int main(int argc, char *argv[]) {
index 0af425e4914ffc31ef1e3cf3dc7816ec969990bc..e587fe79e7a90903fc4fa477b5ca04351d4b8912 100644 (file)
@@ -44,10 +44,11 @@ typedef void (*free_func_t)(void *p);
 
 #define malloc0(n) (calloc(1, (n) ?: 1))
 
-static inline void *mfree(void *memory) {
-        free(memory);
-        return NULL;
-}
+#define mfree(memory)                           \
+        ({                                      \
+                free(memory);                   \
+                (typeof(memory)) NULL;          \
+        })
 
 #define free_and_replace(a, b)                  \
         ({                                      \
index 1ff6160dc88d86ad606a6ba7f45b07d0c3b31ac7..5bf7c03c00ec8e7cc957d331a4d41236ea7b55c7 100644 (file)
@@ -160,6 +160,24 @@ bool cg_freezer_supported(void) {
         return supported;
 }
 
+bool cg_kill_supported(void) {
+        static thread_local int supported = -1;
+
+        if (supported >= 0)
+                return supported;
+
+        if (cg_all_unified() <= 0)
+                supported = false;
+        else if (access("/sys/fs/cgroup/init.scope/cgroup.kill", F_OK) < 0) {
+                if (errno != ENOENT)
+                        log_debug_errno(errno, "Failed to check if cgroup.kill is available, assuming not: %m");
+                supported = false;
+        } else
+                supported = true;
+
+        return supported;
+}
+
 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
         _cleanup_free_ char *fs = NULL;
         int r;
@@ -358,6 +376,29 @@ int cg_kill(
         return cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads");
 }
 
+int cg_kill_kernel_sigkill(const char *controller, const char *path) {
+        /* Kills the cgroup at `path` directly by writing to its cgroup.kill file.
+         * This sends SIGKILL to all processes in the cgroup and has the advantage of
+         * being completely atomic, unlike cg_kill_items. */
+        int r;
+        _cleanup_free_ char *killfile = NULL;
+
+        assert(path);
+
+        if (!cg_kill_supported())
+                return -EOPNOTSUPP;
+
+        r = cg_get_path(controller, path, "cgroup.kill", &killfile);
+        if (r < 0)
+                return r;
+
+        r = write_string_file(killfile, "1", WRITE_STRING_FILE_DISABLE_BUFFER);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 int cg_kill_recursive(
                 const char *controller,
                 const char *path,
@@ -375,38 +416,46 @@ int cg_kill_recursive(
         assert(path);
         assert(sig >= 0);
 
-        if (!s) {
-                s = allocated_set = set_new(NULL);
-                if (!s)
-                        return -ENOMEM;
-        }
+        if (sig == SIGKILL && cg_kill_supported() &&
+            !FLAGS_SET(flags, CGROUP_IGNORE_SELF) && !s && !log_kill) {
+                /* ignore CGROUP_SIGCONT, since this is a no-op alongside SIGKILL */
+                ret = cg_kill_kernel_sigkill(controller, path);
+                if (ret < 0)
+                        return ret;
+        } else {
+                if (!s) {
+                        s = allocated_set = set_new(NULL);
+                        if (!s)
+                                return -ENOMEM;
+                }
 
-        ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata);
+                ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata);
 
-        r = cg_enumerate_subgroups(controller, path, &d);
-        if (r < 0) {
-                if (ret >= 0 && r != -ENOENT)
-                        return r;
+                r = cg_enumerate_subgroups(controller, path, &d);
+                if (r < 0) {
+                        if (ret >= 0 && r != -ENOENT)
+                                return r;
 
-                return ret;
-        }
+                        return ret;
+                }
 
-        while ((r = cg_read_subgroup(d, &fn)) > 0) {
-                _cleanup_free_ char *p = NULL;
+                while ((r = cg_read_subgroup(d, &fn)) > 0) {
+                        _cleanup_free_ char *p = NULL;
 
-                p = path_join(empty_to_root(path), fn);
-                free(fn);
-                if (!p)
-                        return -ENOMEM;
+                        p = path_join(empty_to_root(path), fn);
+                        free(fn);
+                        if (!p)
+                                return -ENOMEM;
 
-                r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata);
-                if (r != 0 && ret >= 0)
+                        r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata);
+                        if (r != 0 && ret >= 0)
+                                ret = r;
+                }
+                if (ret >= 0 && r < 0)
                         ret = r;
         }
-        if (ret >= 0 && r < 0)
-                ret = r;
 
-        if (flags & CGROUP_REMOVE) {
+        if (FLAGS_SET(flags, CGROUP_REMOVE)) {
                 r = cg_rmdir(controller, path);
                 if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
                         return r;
index ce2f4c6589bddbd8998c3884fec05c9ce853a3e0..b2dd9b56a54662883aef87c33ff0f67ba320d0f4 100644 (file)
@@ -172,6 +172,7 @@ typedef enum CGroupFlags {
 typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
 
 int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
+int cg_kill_kernel_sigkill(const char *controller, const char *path);
 int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
 
 int cg_split_spec(const char *spec, char **ret_controller, char **ret_path);
@@ -272,6 +273,7 @@ int cg_kernel_controllers(Set **controllers);
 
 bool cg_ns_supported(void);
 bool cg_freezer_supported(void);
+bool cg_kill_supported(void);
 
 int cg_all_unified(void);
 int cg_hybrid_unified(void);
index 256b7187c2e8ed54a64e549b711850bbaef441c3..e488fff9f020604e6aaba71808707ad75945f313 100644 (file)
 #define LIST_FOREACH_SAFE(name,i,n,head)                                \
         for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
 
-#define LIST_FOREACH_BEFORE(name,i,p)                                   \
-        for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev)
-
-#define LIST_FOREACH_AFTER(name,i,p)                                    \
-        for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
+#define LIST_FOREACH_BACKWARDS(name,i,p)                                \
+        for ((i) = (p); (i); (i) = (i)->name##_prev)
 
 /* Iterate through all the members of the list p is included in, but skip over p */
 #define LIST_FOREACH_OTHERS(name,i,p)                                   \
index 0b04278ab47a6deaa6a7e89732a7fe8a5a78e1e6..e2b543cb8f26a95120dee151388468f347749223 100644 (file)
@@ -71,6 +71,16 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const
         return memmem(haystack, haystacklen, needle, needlelen);
 }
 
+static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+        const uint8_t *p;
+
+        p = memmem_safe(haystack, haystacklen, needle, needlelen);
+        if (!p)
+                return NULL;
+
+        return (uint8_t*) p + needlelen;
+}
+
 #if HAVE_EXPLICIT_BZERO
 static inline void* explicit_bzero_safe(void *p, size_t l) {
         if (l > 0)
index 4aebb6541ea153c6832fd445881cffb225fca9e4..fe799da20b6ce73071f965fcf19a224f60d76ab2 100644 (file)
@@ -639,7 +639,7 @@ static int check_x_access(const char *path, int *ret_fd) {
         return 0;
 }
 
-int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) {
+int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd) {
         int last_error, r;
         const char *p = NULL;
 
@@ -647,6 +647,25 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
 
         if (is_path(name)) {
                 _cleanup_close_ int fd = -1;
+                _cleanup_free_ char *path_name = NULL;
+
+                /* Function chase_symlinks() is invoked only when root is not NULL,
+                 * as using it regardless of root value would alter the behavior
+                 * of existing callers for example: /bin/sleep would become
+                 * /usr/bin/sleep when find_executables is called. Hence, this function
+                 * should be invoked when needed to avoid unforeseen regression or other
+                 * complicated changes. */
+                if (root) {
+                        r = chase_symlinks(name,
+                                           root,
+                                           CHASE_PREFIX_ROOT,
+                                           &path_name,
+                                           /* ret_fd= */ NULL); /* prefix root to name in case full paths are not specified */
+                        if (r < 0)
+                                return r;
+
+                        name = path_name;
+                }
 
                 r = check_x_access(name, ret_fd ? &fd : NULL);
                 if (r < 0)
@@ -690,6 +709,23 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
                 if (!path_extend(&element, name))
                         return -ENOMEM;
 
+                if (root) {
+                        char *path_name;
+
+                        r = chase_symlinks(element,
+                                           root,
+                                           CHASE_PREFIX_ROOT,
+                                           &path_name,
+                                           /* ret_fd= */ NULL);
+                        if (r < 0) {
+                                if (r != -EACCES)
+                                        last_error = r;
+                                continue;
+                        }
+
+                        free_and_replace(element, path_name);
+                }
+
                 r = check_x_access(element, ret_fd ? &fd : NULL);
                 if (r < 0) {
                         /* PATH entries which we don't have access to are ignored, as per tradition. */
index 26e7362d1f5865bb0aa5c596a524e40f7813bf33..0d69145497d50a51d6d44856355a629087e71a6e 100644 (file)
@@ -99,9 +99,9 @@ int path_strv_make_absolute_cwd(char **l);
 char** path_strv_resolve(char **l, const char *root);
 char** path_strv_resolve_uniq(char **l, const char *root);
 
-int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd);
+int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd);
 static inline int find_executable(const char *name, char **ret_filename) {
-        return find_executable_full(name, true, ret_filename, NULL);
+        return find_executable_full(name, /* root= */ NULL, true, ret_filename, NULL);
 }
 
 bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
index 78f22f1ac918d4ef844a2230d5b85911ff1b0751..5d1111fd712be76261241da9358c02cd0695a474 100644 (file)
@@ -20,6 +20,7 @@
 #define SPECIAL_HIBERNATE_TARGET "hibernate.target"
 #define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
 #define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target"
+#define SPECIAL_FACTORY_RESET_TARGET "factory-reset.target"
 
 /* Special boot targets */
 #define SPECIAL_RESCUE_TARGET "rescue.target"
index 264189c36b93957af37bd1347ff9a7acd6268001..b1a0e313ce9bfee7668bcf7cf88ce3f7ac4d299d 100644 (file)
@@ -159,12 +159,11 @@ static int get_file_version(int fd, char **v) {
         if (buf == MAP_FAILED)
                 return log_error_errno(errno, "Failed to memory map EFI binary: %m");
 
-        s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
+        s = mempmem_safe(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
         if (!s)
                 goto finish;
-        s += 17;
 
-        e = memmem(s, st.st_size - (s - buf), " ####", 5);
+        e = memmem_safe(s, st.st_size - (s - buf), " ####", 5);
         if (!e || e - s < 3) {
                 r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
                 goto finish;
index ff364695f352982871e37bda4480b6b89f893c76..3e179851b0805cd8ddd0f90dbf6576da9d19baf6 100644 (file)
@@ -245,7 +245,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
 
         err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, (CHAR16*) L"\\loader\\random-seed", EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
         if (EFI_ERROR(err)) {
-                if (err != EFI_NOT_FOUND)
+                if (err != EFI_NOT_FOUND && err != EFI_WRITE_PROTECTED)
                         Print(L"Failed to open random seed file: %r\n", err);
                 return err;
         }
index 6f4e5933d30506ffdd873f417ef73be56bddcba2..0ca4d17b37110ced3b996876766401f7f0183263 100644 (file)
@@ -17,6 +17,12 @@ UINT64 ticks_read(VOID) {
         __asm__ volatile ("rdtsc" : "=A" (val));
         return val;
 }
+#elif defined(__aarch64__)
+UINT64 ticks_read(VOID) {
+        UINT64 val;
+        __asm__ volatile ("mrs %0, cntpct_el0" : "=r" (val));
+        return val;
+}
 #else
 UINT64 ticks_read(VOID) {
         UINT64 val = 1;
@@ -24,6 +30,13 @@ UINT64 ticks_read(VOID) {
 }
 #endif
 
+#if defined(__aarch64__)
+UINT64 ticks_freq(VOID) {
+        UINT64 freq;
+        __asm__ volatile ("mrs %0, cntfrq_el0": "=r" (freq));
+        return freq;
+}
+#else
 /* count TSC ticks during a millisecond delay */
 UINT64 ticks_freq(VOID) {
         UINT64 ticks_start, ticks_end;
@@ -34,6 +47,7 @@ UINT64 ticks_freq(VOID) {
 
         return (ticks_end - ticks_start) * 1000UL;
 }
+#endif
 
 UINT64 time_usec(VOID) {
         UINT64 ticks;
index 5ed5ceb290429f7a614942bda1abf85e3c582356..66841984feab5fd42e0c359805349cefd479a340 100644 (file)
@@ -771,11 +771,11 @@ static Unit *device_following(Unit *u) {
                 return NULL;
 
         /* Make everybody follow the unit that's named after the sysfs path */
-        LIST_FOREACH_AFTER(same_sysfs, other, d)
+        LIST_FOREACH(same_sysfs, other, d->same_sysfs_next)
                 if (startswith(UNIT(other)->id, "sys-"))
                         return UNIT(other);
 
-        LIST_FOREACH_BEFORE(same_sysfs, other, d) {
+        LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
                 if (startswith(UNIT(other)->id, "sys-"))
                         return UNIT(other);
 
@@ -802,13 +802,13 @@ static int device_following_set(Unit *u, Set **_set) {
         if (!set)
                 return -ENOMEM;
 
-        LIST_FOREACH_AFTER(same_sysfs, other, d) {
+        LIST_FOREACH(same_sysfs, other, d->same_sysfs_next) {
                 r = set_put(set, other);
                 if (r < 0)
                         return r;
         }
 
-        LIST_FOREACH_BEFORE(same_sysfs, other, d) {
+        LIST_FOREACH_BACKWARDS(same_sysfs, other, d->same_sysfs_prev) {
                 r = set_put(set, other);
                 if (r < 0)
                         return r;
index 5bee44ac7b512c9616514c6590af599258c9aa1a..c1fad61554825ae48f3f4b8212f55f0b1112ced7 100644 (file)
@@ -4350,7 +4350,7 @@ static int exec_child(
 
         _cleanup_free_ char *executable = NULL;
         _cleanup_close_ int executable_fd = -1;
-        r = find_executable_full(command->path, false, &executable, &executable_fd);
+        r = find_executable_full(command->path, /* root= */ NULL, false, &executable, &executable_fd);
         if (r < 0) {
                 if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
                         log_unit_struct_errno(unit, LOG_INFO, r,
index eb24245fb353281ae6e7f6f400e237f6de76c010..0914f92a2e0b09d4c5d308a67e831596f5860e16 100644 (file)
@@ -2908,7 +2908,7 @@ int main(int argc, char *argv[]) {
 
         before_startup = now(CLOCK_MONOTONIC);
 
-        r = manager_startup(m, arg_serialization, fds);
+        r = manager_startup(m, arg_serialization, fds, /* root= */ NULL);
         if (r < 0) {
                 error_message = "Failed to start up manager";
                 goto finish;
index d76b7b2b16cb8611e83c7735903189bbd66bc73b..677b08e0984d361565e19fc624e3d117db41c6c9 100644 (file)
@@ -1727,7 +1727,7 @@ void manager_reloading_stopp(Manager **m) {
         }
 }
 
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *root) {
         int r;
 
         assert(m);
@@ -1736,7 +1736,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
          * but we should not touch the real generator directories. */
         r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope,
                               MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
-                              NULL);
+                              root);
         if (r < 0)
                 return log_error_errno(r, "Failed to initialize path lookup table: %m");
 
index 284ea42a9dd43a5b989ac91131d942784f48a490..4ce43684746f5efe6966e937b299a8b6ce729a03 100644 (file)
@@ -470,7 +470,7 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
 Manager* manager_free(Manager *m);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
+int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *root);
 
 Job *manager_get_job(Manager *m, uint32_t id);
 Unit *manager_get_unit(Manager *m, const char *name);
index 42d2e0242ecd39c297987e03e80d14ece874db8e..48ba5c766492c0455080fbddbad15147b2091e7d 100644 (file)
@@ -1323,11 +1323,11 @@ static Unit *swap_following(Unit *u) {
         if (streq_ptr(s->what, s->devnode))
                 return NULL;
 
-        LIST_FOREACH_AFTER(same_devnode, other, s)
+        LIST_FOREACH(same_devnode, other, s->same_devnode_next)
                 if (streq_ptr(other->what, other->devnode))
                         return UNIT(other);
 
-        LIST_FOREACH_BEFORE(same_devnode, other, s) {
+        LIST_FOREACH_BACKWARDS(same_devnode, other, s->same_devnode_prev) {
                 if (streq_ptr(other->what, other->devnode))
                         return UNIT(other);
 
index 8ce94ccb75e641c216e936dde611fcedad15781e..5cc66ab164f2d9493baa2b506833ea667e152b82 100644 (file)
@@ -5497,10 +5497,19 @@ const char *unit_label_path(const Unit *u) {
         /* Returns the file system path to use for MAC access decisions, i.e. the file to read the SELinux label off
          * when validating access checks. */
 
+        if (IN_SET(u->load_state, UNIT_MASKED, UNIT_NOT_FOUND, UNIT_MERGED))
+                return NULL; /* Shortcut things if we know there is no real, relevant unit file around */
+
         p = u->source_path ?: u->fragment_path;
         if (!p)
                 return NULL;
 
+        if (IN_SET(u->load_state, UNIT_LOADED, UNIT_BAD_SETTING, UNIT_ERROR))
+                return p; /* Shortcut things, if we successfully loaded at least some stuff from the unit file */
+
+        /* Not loaded yet, we need to go to disk */
+        assert(u->load_state == UNIT_STUB);
+
         /* If a unit is masked, then don't read the SELinux label of /dev/null, as that really makes no sense */
         if (null_or_empty_path(p) > 0)
                 return NULL;
index 242c72a43ac8282877463a46c4476273cc79292c..c7819b1a8d0e07d29bb9f686203d6c19fdb96db9 100644 (file)
@@ -212,6 +212,22 @@ _public_ int cryptsetup_token_validate(
                 }
         }
 
+        /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded to SHA256 */
+        w = json_variant_by_key(v, "tpm2-pcr-bank");
+        if (w) {
+                /* The PCR bank field is optional */
+
+                if (!json_variant_is_string(w)) {
+                        crypt_log_debug(cd, "TPM2 PCR bank is not a string.");
+                        return 1;
+                }
+
+                if (tpm2_pcr_bank_from_string(json_variant_string(w)) < 0) {
+                        crypt_log_debug(cd, "TPM2 PCR bank invalid or not supported: %s.", json_variant_string(w));
+                        return 1;
+                }
+        }
+
         w = json_variant_by_key(v, "tpm2-blob");
         if (!w || !json_variant_is_string(w)) {
                 crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-blob' field.");
index bafc7b8f960bb5d2a75dbeea1d8edc1cd6166471..bae67be09f1434929b60d87f4833b5a7d09028c8 100644 (file)
@@ -451,6 +451,10 @@ static int add_mount(
                 "\n"
                 "[Mount]\n");
 
+        r = write_what(f, what);
+        if (r < 0)
+                return r;
+
         if (original_where)
                 fprintf(f, "# Canonicalized from %s\n", original_where);
 
@@ -459,10 +463,6 @@ static int add_mount(
                 return log_oom();
         fprintf(f, "Where=%s\n", where_escaped);
 
-        r = write_what(f, what);
-        if (r < 0)
-                return r;
-
         if (!isempty(fstype) && !streq(fstype, "auto")) {
                 _cleanup_free_ char *t = NULL;
 
index cb77454e0f6983015e216fd1f94601828548c31d..e1cd495102c54bb697ac3c357b3e408c73d25b54 100644 (file)
@@ -10,6 +10,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "io-util.h"
+#include "memory-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "pull-common.h"
@@ -342,18 +343,18 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
 
         line = strjoina(job->checksum, " *", fn, "\n");
 
-        p = memmem(checksum_job->payload,
-                   checksum_job->payload_size,
-                   line,
-                   strlen(line));
+        p = memmem_safe(checksum_job->payload,
+                        checksum_job->payload_size,
+                        line,
+                        strlen(line));
 
         if (!p) {
                 line = strjoina(job->checksum, "  ", fn, "\n");
 
-                p = memmem(checksum_job->payload,
-                        checksum_job->payload_size,
-                        line,
-                        strlen(line));
+                p = memmem_safe(checksum_job->payload,
+                                checksum_job->payload_size,
+                                line,
+                                strlen(line));
         }
 
         if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n'))
index b067afc800f614a7ba003b01cc806c10bc5faa14..d4ab9df992b5dadaf558839c8bc599d56c54e61d 100644 (file)
@@ -1134,30 +1134,24 @@ static int client_parse_message(
 
                 switch (optcode) {
                 case SD_DHCP6_OPTION_CLIENTID:
-                        if (clientid) {
-                                log_dhcp6_client(client, "%s contains multiple clientids",
-                                                 dhcp6_message_type_to_string(message->type));
-                                return -EINVAL;
-                        }
+                        if (clientid)
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple clientids",
+                                                              dhcp6_message_type_to_string(message->type));
 
                         if (optlen != client->duid_len ||
-                            memcmp(&client->duid, optval, optlen) != 0) {
-                                log_dhcp6_client(client, "%s DUID does not match",
-                                                 dhcp6_message_type_to_string(message->type));
+                            memcmp(&client->duid, optval, optlen) != 0)
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s DUID does not match",
+                                                              dhcp6_message_type_to_string(message->type));
 
-                                return -EINVAL;
-                        }
                         clientid = true;
 
                         break;
 
                 case SD_DHCP6_OPTION_SERVERID:
                         r = dhcp6_lease_get_serverid(lease, NULL, NULL);
-                        if (r >= 0) {
-                                log_dhcp6_client(client, "%s contains multiple serverids",
-                                                 dhcp6_message_type_to_string(message->type));
-                                return -EINVAL;
-                        }
+                        if (r >= 0)
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple serverids",
+                                                              dhcp6_message_type_to_string(message->type));
 
                         r = dhcp6_lease_set_serverid(lease, optval, optlen);
                         if (r < 0)
@@ -1180,20 +1174,16 @@ static int client_parse_message(
                         if (status < 0)
                                 return status;
 
-                        if (status > 0) {
-                                log_dhcp6_client(client, "%s Status %s",
-                                                 dhcp6_message_type_to_string(message->type),
-                                                 dhcp6_message_status_to_string(status));
-
-                                return -EINVAL;
-                        }
+                        if (status > 0)
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s Status %s",
+                                                              dhcp6_message_type_to_string(message->type),
+                                                              dhcp6_message_status_to_string(status));
 
                         break;
 
                 case SD_DHCP6_OPTION_IA_NA:
                         if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
-                                log_dhcp6_client(client, "Information request ignoring IA NA option");
-
+                                log_dhcp6_client(client, "Ignoring IA NA option in information requesting mode.");
                                 break;
                         }
 
@@ -1210,23 +1200,20 @@ static int client_parse_message(
                         if (r < 0)
                                 return r;
 
-                        if (client->ia_na.ia_na.id != iaid_lease) {
-                                log_dhcp6_client(client, "%s has wrong IAID for IA NA",
-                                                 dhcp6_message_type_to_string(message->type));
-                                return -EINVAL;
-                        }
+                        if (client->ia_na.ia_na.id != iaid_lease)
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has wrong IAID for IA NA",
+                                                              dhcp6_message_type_to_string(message->type));
 
                         if (lease->ia.addresses) {
                                 lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
-                                lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1));
+                                lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
                         }
 
                         break;
 
                 case SD_DHCP6_OPTION_IA_PD:
                         if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
-                                log_dhcp6_client(client, "Information request ignoring IA PD option");
-
+                                log_dhcp6_client(client, "Ignoring IA PD option in information requesting mode.");
                                 break;
                         }
 
@@ -1243,11 +1230,9 @@ static int client_parse_message(
                         if (r < 0)
                                 return r;
 
-                        if (client->ia_pd.ia_pd.id != iaid_lease) {
-                                log_dhcp6_client(client, "%s has wrong IAID for IA PD",
-                                                 dhcp6_message_type_to_string(message->type));
-                                return -EINVAL;
-                        }
+                        if (client->ia_pd.ia_pd.id != iaid_lease)
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has wrong IAID for IA PD",
+                                                              dhcp6_message_type_to_string(message->type));
 
                         if (lease->pd.addresses) {
                                 lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
@@ -1309,35 +1294,28 @@ static int client_parse_message(
                 pos += offsetof(DHCP6Option, data) + optlen;
         }
 
-        if (ia_na_status > 0 && ia_pd_status > 0) {
-                log_dhcp6_client(client, "No IA_PD prefix or IA_NA address received. Ignoring.");
-                return -EINVAL;
-        }
+        if (ia_na_status > 0 && ia_pd_status > 0)
+                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "No IA_PD prefix or IA_NA address received. Ignoring.");
 
-        if (!clientid) {
-                log_dhcp6_client(client, "%s has incomplete options",
-                                 dhcp6_message_type_to_string(message->type));
-                return -EINVAL;
-        }
+        if (!clientid)
+                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has incomplete options",
+                                              dhcp6_message_type_to_string(message->type));
 
         if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
                 r = dhcp6_lease_get_serverid(lease, NULL, NULL);
-                if (r < 0) {
-                        log_dhcp6_client(client, "%s has no server id",
-                                         dhcp6_message_type_to_string(message->type));
-                        return -EINVAL;
-                }
+                if (r < 0)
+                        return log_dhcp6_client_errno(client, r, "%s has no server id",
+                                                      dhcp6_message_type_to_string(message->type));
+        }
 
-        } else {
-                if (lease->ia.addresses) {
-                        lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
-                        lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
-                }
+        if (lease->ia.addresses) {
+                lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
+                lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
+        }
 
-                if (lease->pd.addresses) {
-                        lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
-                        lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
-                }
+        if (lease->pd.addresses) {
+                lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
+                lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
         }
 
         client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
index b408d657a5e7f031755e3cfe6f85ffb31edb37e2..4b8d73c3e083c054542941e49c72c7032fa018e6 100644 (file)
@@ -173,12 +173,12 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
         if (!d)
                 return 0;
 
-        e = memmem(d + 2, b->rbuffer_size - (d - (char*) b->rbuffer) - 2, "\r\n", 2);
+        e = memmem_safe(d + 2, b->rbuffer_size - (d - (char*) b->rbuffer) - 2, "\r\n", 2);
         if (!e)
                 return 0;
 
         if (b->accept_fd) {
-                f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2);
+                f = memmem_safe(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2);
                 if (!f)
                         return 0;
 
@@ -399,7 +399,7 @@ static int bus_socket_auth_verify_server(sd_bus *b) {
         for (;;) {
                 /* Check if line is complete */
                 line = (char*) b->rbuffer + b->auth_rbegin;
-                e = memmem(line, b->rbuffer_size - b->auth_rbegin, "\r\n", 2);
+                e = memmem_safe(line, b->rbuffer_size - b->auth_rbegin, "\r\n", 2);
                 if (!e)
                         return processed;
 
index 8ed066c25e53a15d9fb2fb781a56fb5785704805..e1729109482b031d9f0a896ac4b369d8b325b59d 100644 (file)
@@ -27,6 +27,7 @@ const char* manager_target_for_action(HandleAction handle) {
                 [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
                 [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
                 [HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
+                [HANDLE_FACTORY_RESET] = SPECIAL_FACTORY_RESET_TARGET,
         };
 
         assert(handle >= 0);
@@ -51,6 +52,7 @@ int manager_handle_action(
                 [HANDLE_HIBERNATE] = "Hibernating...",
                 [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
                 [HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...",
+                [HANDLE_FACTORY_RESET] = "Performing factory reset...",
         };
 
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -179,6 +181,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
         [HANDLE_HIBERNATE] = "hibernate",
         [HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
         [HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
+        [HANDLE_FACTORY_RESET] = "factory-reset",
         [HANDLE_LOCK] = "lock",
 };
 
index 0baad37a84c92cea1ecd6a82dd73b35babd1e57b..ec2fece2b7b056ebbae95abff228106a199a6b4b 100644 (file)
@@ -14,6 +14,7 @@ typedef enum HandleAction {
         HANDLE_HYBRID_SLEEP,
         HANDLE_SUSPEND_THEN_HIBERNATE,
         HANDLE_LOCK,
+        HANDLE_FACTORY_RESET,
         _HANDLE_ACTION_MAX,
         _HANDLE_ACTION_INVALID = -EINVAL,
 } HandleAction;
index ccda0bdec4d187e4f10fc3171aa3c4618155e807..6e9dde1c15576ab6ac3106767d979e42b3faa80d 100644 (file)
@@ -1491,41 +1491,59 @@ static int have_multiple_sessions(
         return false;
 }
 
-static int bus_manager_log_shutdown(
-                Manager *m,
-                const char *unit_name) {
-
-        const char *p, *q;
-
+_printf_(2, 0)
+static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) {
         assert(m);
-        assert(unit_name);
-
-        if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
-                p = "MESSAGE=System is powering down";
-                q = "SHUTDOWN=power-off";
-        } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
-                p = "MESSAGE=System is rebooting";
-                q = "SHUTDOWN=reboot";
-        } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
-                p = "MESSAGE=System is halting";
-                q = "SHUTDOWN=halt";
-        } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
-                p = "MESSAGE=System is rebooting with kexec";
-                q = "SHUTDOWN=kexec";
-        } else {
-                p = "MESSAGE=System is shutting down";
-                q = NULL;
-        }
 
         if (isempty(m->wall_message))
                 p = strjoina(p, ".");
         else
                 p = strjoina(p, " (", m->wall_message, ").");
 
-        return log_struct(LOG_NOTICE,
-                          "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
-                          p,
-                          q);
+        return log_struct(LOG_NOTICE, d, p, q);
+}
+
+static int bus_manager_log_shutdown(
+                Manager *m,
+                const char *unit_name) {
+
+        assert(m);
+        assert(unit_name);
+
+        if (streq(unit_name, SPECIAL_POWEROFF_TARGET))
+                return log_with_wall_message(m,
+                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
+                                             "MESSAGE=System is powering down",
+                                             "SHUTDOWN=power-off");
+
+        if (streq(unit_name, SPECIAL_REBOOT_TARGET))
+                return log_with_wall_message(m,
+                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
+                                             "MESSAGE=System is rebooting",
+                                             "SHUTDOWN=reboot");
+
+        if (streq(unit_name, SPECIAL_HALT_TARGET))
+                return log_with_wall_message(m,
+                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
+                                             "MESSAGE=System is halting",
+                                             "SHUTDOWN=halt");
+
+        if (streq(unit_name, SPECIAL_KEXEC_TARGET))
+                return log_with_wall_message(m,
+                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
+                                             "MESSAGE=System is rebooting with kexec",
+                                             "SHUTDOWN=kexec");
+
+        if (streq(unit_name, SPECIAL_FACTORY_RESET_TARGET))
+                return log_with_wall_message(m,
+                                             "MESSAGE_ID=" SD_MESSAGE_FACTORY_RESET_STR,
+                                             "MESSAGE=System is performing factory reset",
+                                             NULL);
+
+        return log_with_wall_message(m,
+                                     "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
+                                     "MESSAGE=System is shutting down",
+                                     NULL);
 }
 
 static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
index 249d780887eeca0b972bfa1ab29049dc10e26f43..2b201e271eeb70dd8863dfe53dccfb54a3193fc4 100644 (file)
@@ -96,113 +96,64 @@ const DUID *link_get_duid(Link *link, int family) {
         return duid;
 }
 
-static int link_configure_and_start_dhcp_delayed(Link *link) {
-        int r;
-
-        assert(link);
-
-        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
-                return 0;
-
-        if (!link->dhcp_client) {
-                r = dhcp4_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (!link->dhcp6_client) {
-                r = dhcp6_configure(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (link->set_flags_messages > 0)
-                return 0;
-
-        if (!link_has_carrier(link))
-                return 0;
-
-        r = dhcp4_start(link);
-        if (r < 0)
-                return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
-
-        r = ndisc_start(link);
-        if (r < 0)
-                return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
-
-        r = dhcp6_start(link);
-        if (r < 0)
-                return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
-
-        return 0;
-}
-
 static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         Manager *manager = userdata;
         const sd_bus_error *e;
         const void *a;
         size_t sz;
-        Link *link;
         int r;
 
         assert(m);
         assert(manager);
 
+        /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
+         * even if the method fails. */
+        manager->has_product_uuid = true;
+
         e = sd_bus_message_get_error(m);
         if (e) {
                 r = sd_bus_error_get_errno(e);
                 log_warning_errno(r, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
                                   bus_error_message(e, r));
-                goto configure;
+                return 0;
         }
 
         r = sd_bus_message_read_array(m, 'y', &a, &sz);
         if (r < 0) {
                 log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
-                goto configure;
+                return 0;
         }
 
         if (sz != sizeof(sd_id128_t)) {
                 log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
-                goto configure;
+                return 0;
         }
 
+        log_debug("Successfully obtained product UUID");
+
         memcpy(&manager->duid_product_uuid.raw_data, a, sz);
         manager->duid_product_uuid.raw_data_len = sz;
 
-configure:
-        /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
-         * even if the method fails. */
-        manager->has_product_uuid = true;
-
-        while ((link = set_steal_first(manager->links_requesting_uuid))) {
-                r = link_configure_and_start_dhcp_delayed(link);
-                if (r < 0)
-                        link_enter_failed(link);
-
-                link_unref(link);
-        }
-
-        manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
-
-        return 1;
+        return 0;
 }
 
 int manager_request_product_uuid(Manager *m) {
+        static bool bus_method_is_called = false;
         int r;
 
         assert(m);
 
-        if (m->product_uuid_requested)
+        if (bus_method_is_called)
                 return 0;
 
-        log_debug("Requesting product UUID");
-
-        if (sd_bus_is_ready(m->bus) <= 0) {
+        if (sd_bus_is_ready(m->bus) <= 0 && !m->product_uuid_requested) {
                 log_debug("Not connected to system bus, requesting product UUID later.");
+                m->product_uuid_requested = true;
                 return 0;
         }
 
+        m->product_uuid_requested = false;
+
         r = sd_bus_call_method_async(
                         m->bus,
                         NULL,
@@ -217,7 +168,9 @@ int manager_request_product_uuid(Manager *m) {
         if (r < 0)
                 return log_warning_errno(r, "Failed to get product UUID: %m");
 
-        m->product_uuid_requested = true;
+        log_debug("Requesting product UUID.");
+
+        bus_method_is_called = true;
 
         return 0;
 }
@@ -242,15 +195,11 @@ int dhcp_configure_duid(Link *link, const DUID *duid) {
         if (r < 0) {
                 log_link_warning_errno(link, r,
                                        "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
+
+                m->has_product_uuid = true; /* Do not request UUID again on failure. */
                 return 1;
         }
 
-        r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
-        if (r < 0)
-                return log_oom();
-        if (r > 0)
-                link_ref(link);
-
         return 0;
 }
 
@@ -543,8 +492,8 @@ int config_parse_iaid(const char *unit,
                 network->dhcp_iaid = iaid;
                 network->dhcp_iaid_set = true;
                 if (!network->dhcp6_iaid_set_explicitly) {
-                        /* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6.
-                         * If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */
+                        /* Backward compatibility. Previously, IAID is shared by DHCPv4 and DHCPv6.
+                         * If DHCPv6 IAID is not specified explicitly, then use DHCPv4 IAID for DHCPv6. */
                         network->dhcp6_iaid = iaid;
                         network->dhcp6_iaid_set = true;
                 }
@@ -1036,7 +985,7 @@ int config_parse_manager_duid_type(
 
         assert(manager);
 
-        /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
+        /* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
 
         r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
         if (r < 0)
@@ -1066,7 +1015,7 @@ int config_parse_network_duid_type(
         if (r < 0)
                 return r;
 
-        /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
+        /* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
         return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
 }
 
@@ -1161,7 +1110,7 @@ int config_parse_manager_duid_rawdata(
 
         assert(manager);
 
-        /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */
+        /* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
 
         r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager);
         if (r < 0)
@@ -1191,6 +1140,6 @@ int config_parse_network_duid_rawdata(
         if (r < 0)
                 return r;
 
-        /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */
+        /* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
         return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network);
 }
index c986031b87bce63ad4c9a3723ecf48a31fc6f02a..12fb85bf9020f2640cb06ad4c53302f39f47d06e 100644 (file)
@@ -1311,7 +1311,7 @@ static int dhcp4_set_hostname(Link *link) {
         else {
                 r = gethostname_strict(&hostname);
                 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to get hostname: %m");
 
                 hn = hostname;
         }
@@ -1319,9 +1319,9 @@ static int dhcp4_set_hostname(Link *link) {
         r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
         if (r == -EINVAL && hostname)
                 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
-                log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
+                log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
         else if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname: %m");
 
         return 0;
 }
@@ -1351,7 +1351,7 @@ static int dhcp4_set_client_identifier(Link *link) {
                                                          duid->raw_data_len > 0 ? duid->raw_data : NULL,
                                                          duid->raw_data_len);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m");
                 break;
         }
         case DHCP_CLIENT_ID_DUID_ONLY: {
@@ -1367,7 +1367,7 @@ static int dhcp4_set_client_identifier(Link *link) {
                                                     duid->raw_data_len > 0 ? duid->raw_data : NULL,
                                                     duid->raw_data_len);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set DUID: %m");
                 break;
         }
         case DHCP_CLIENT_ID_MAC: {
@@ -1385,7 +1385,7 @@ static int dhcp4_set_client_identifier(Link *link) {
                                                  hw_addr,
                                                  hw_addr_len);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set client ID: %m");
                 break;
         }
         default:
@@ -1395,15 +1395,6 @@ static int dhcp4_set_client_identifier(Link *link) {
         return 0;
 }
 
-static int dhcp4_configure_duid(Link *link) {
-        assert(link);
-
-        if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
-                return 1;
-
-        return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
-}
-
 static int dhcp4_set_request_address(Link *link) {
         Address *a;
 
@@ -1424,7 +1415,7 @@ static int dhcp4_set_request_address(Link *link) {
         if (!a)
                 return 0;
 
-        log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
+        log_link_debug(link, "DHCPv4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
 
         return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
 }
@@ -1445,15 +1436,15 @@ static bool link_needs_dhcp_broadcast(Link *link) {
         if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
                 r = parse_boolean(val);
                 if (r < 0)
-                        log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
+                        log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
                 else
-                        log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
+                        log_link_debug(link, "DHCPv4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
 
         }
         return r == true;
 }
 
-int dhcp4_configure(Link *link) {
+static int dhcp4_configure(Link *link) {
         sd_dhcp_option *send_option;
         void *request_options;
         int r;
@@ -1461,88 +1452,81 @@ int dhcp4_configure(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (!link_dhcp4_enabled(link))
-                return 0;
-
         if (link->dhcp_client)
-                return -EBUSY; /* Already configured. */
-
-        r = dhcp4_configure_duid(link);
-        if (r <= 0)
-                return r;
+                return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv4 client is already configured.");
 
         r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to allocate DHCPv4 client: %m");
 
         r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m");
 
         r = sd_dhcp_client_set_mac(link->dhcp_client,
                                    link->hw_addr.bytes,
                                    link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
                                    link->hw_addr.length, link->iftype);
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MAC address: %m");
 
         r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set ifindex: %m");
 
         r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set callback: %m");
 
         r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m");
 
         if (link->mtu > 0) {
                 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MTU: %m");
         }
 
         if (!link->network->dhcp_anonymize) {
                 if (link->network->dhcp_use_mtu) {
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for MTU: %m");
                 }
 
                 if (link->network->dhcp_use_routes) {
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for static route: %m");
 
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m");
                 }
 
                 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m");
                 }
 
                 if (link->network->dhcp_use_ntp) {
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m");
                 }
 
                 if (link->network->dhcp_use_sip) {
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
                 }
 
                 if (link->network->dhcp_use_timezone) {
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m");
                 }
 
                 SET_FOREACH(request_options, link->network->dhcp_request_options) {
@@ -1550,7 +1534,7 @@ int dhcp4_configure(Link *link) {
 
                         r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for '%u': %m", option);
                 }
 
                 ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
@@ -1558,7 +1542,7 @@ int dhcp4_configure(Link *link) {
                         if (r == -EEXIST)
                                 continue;
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
                 }
 
                 ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
@@ -1566,7 +1550,7 @@ int dhcp4_configure(Link *link) {
                         if (r == -EEXIST)
                                 continue;
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
                 }
 
                 r = dhcp4_set_hostname(link);
@@ -1577,49 +1561,49 @@ int dhcp4_configure(Link *link) {
                         r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
                                                                        link->network->dhcp_vendor_class_identifier);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set vendor class identifier: %m");
                 }
 
                 if (link->network->dhcp_mudurl) {
                         r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m");
                 }
 
                 if (link->network->dhcp_user_class) {
                         r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
                         if (r < 0)
-                                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
                 }
         }
 
         if (link->network->dhcp_client_port > 0) {
                 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m");
         }
 
         if (link->network->dhcp_max_attempts > 0) {
                 r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set max attempts: %m");
         }
 
         if (link->network->dhcp_ip_service_type > 0) {
                 r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m");
         }
 
         if (link->network->dhcp_fallback_lease_lifetime > 0) {
                 r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
                 if (r < 0)
-                        return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
+                        return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed set to lease lifetime: %m");
         }
 
         r = dhcp4_set_request_address(link);
         if (r < 0)
-                return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
+                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set initial DHCPv4 address: %m");
 
         return dhcp4_set_client_identifier(link);
 }
@@ -1642,17 +1626,83 @@ int dhcp4_update_mac(Link *link) {
 }
 
 int dhcp4_start(Link *link) {
+        int r;
+
         assert(link);
 
         if (!link->dhcp_client)
                 return 0;
 
+        if (!link_has_carrier(link))
+                return 0;
+
         if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
                 return 0;
 
-        log_link_debug(link, "Acquiring DHCPv4 lease");
+        r = sd_dhcp_client_start(link->dhcp_client);
+        if (r < 0)
+                return r;
 
-        return sd_dhcp_client_start(link->dhcp_client);
+        return 1;
+}
+
+static int dhcp4_configure_duid(Link *link) {
+        assert(link);
+
+        if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
+                return 1;
+
+        return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
+}
+
+int request_process_dhcp4_client(Request *req) {
+        Link *link;
+        int r;
+
+        assert(req);
+        assert(req->link);
+        assert(req->type == REQUEST_TYPE_DHCP4_CLIENT);
+
+        link = req->link;
+
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                return 0;
+
+        r = dhcp4_configure_duid(link);
+        if (r <= 0)
+                return r;
+
+        r = dhcp4_configure(req->link);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to configure DHCPv4 client: %m");
+
+        r = dhcp4_start(link);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
+
+        log_link_debug(link, "DHCPv4 client is configured%s.",
+                       r > 0 ? ", acquiring DHCPv4 lease" : "");
+
+        return 1;
+}
+
+int link_request_dhcp4_client(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (!link_dhcp4_enabled(link))
+                return 0;
+
+        if (link->dhcp_client)
+                return 0;
+
+        r = link_queue_request(link, REQUEST_TYPE_DHCP4_CLIENT, NULL, false, NULL, NULL, NULL);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv4 client: %m");
+
+        log_link_debug(link, "Requested configuring of the DHCPv4 client.");
+        return 0;
 }
 
 int config_parse_dhcp_max_attempts(
index e41e39fc6e941ade3189914d3d1071124c300809..152c2213b49ec1412fca2595fc74d80ced5530b4 100644 (file)
@@ -4,6 +4,8 @@
 #include "conf-parser.h"
 
 typedef struct Link Link;
+typedef struct Network Network;
+typedef struct Request Request;
 
 typedef enum DHCPClientIdentifier {
         DHCP_CLIENT_ID_MAC,
@@ -18,11 +20,13 @@ typedef enum DHCPClientIdentifier {
 } DHCPClientIdentifier;
 
 void network_adjust_dhcp4(Network *network);
-int dhcp4_configure(Link *link);
 int dhcp4_update_mac(Link *link);
 int dhcp4_start(Link *link);
 int dhcp4_lease_lost(Link *link);
 
+int request_process_dhcp4_client(Request *req);
+int link_request_dhcp4_client(Link *link);
+
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
index f03bf0651b182ac7e1f6b6be3f2a9e49b95dea50..2f755bc4ebb18ef8ae8caa2392e908f7c10efb4c 100644 (file)
@@ -920,7 +920,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
         log_link_full(link,
                       set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG :
                       prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO,
-                      "DHCP6: received PD Prefix %s%s",
+                      "DHCPv6: received PD Prefix %s%s",
                       strna(buf),
                       prefixlen > 64 ? " with prefix length > 64, ignoring." :
                       prefixlen < 48 ? " with prefix length < 48, looks unusual.": "");
@@ -928,7 +928,7 @@ static int dhcp6_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_
         /* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
         r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
         if (r < 0)
-                return log_link_error_errno(link, r, "Failed to store DHCP6 PD prefix %s: %m", strna(buf));
+                return log_link_error_errno(link, r, "Failed to store DHCPv6 PD prefix %s: %m", strna(buf));
         if (r > 0)
                 TAKE_PTR(p);
 
@@ -1393,6 +1393,8 @@ int dhcp6_request_information(Link *link, int ir) {
 }
 
 int dhcp6_start(Link *link) {
+        int r;
+
         assert(link);
 
         if (!link->dhcp6_client)
@@ -1401,6 +1403,9 @@ int dhcp6_start(Link *link) {
         if (!link_dhcp6_enabled(link))
                 return 0;
 
+        if (!link_has_carrier(link))
+                return 0;
+
         if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO)
                 return 0;
 
@@ -1412,9 +1417,11 @@ int dhcp6_start(Link *link) {
         if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0)
                 return 0;
 
-        log_link_debug(link, "Acquiring DHCPv6 lease");
+        r = dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
+        if (r < 0)
+                return r;
 
-        return dhcp6_request_information(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST);
+        return 1;
 }
 
 int dhcp6_request_prefix_delegation(Link *link) {
@@ -1505,7 +1512,7 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
         else {
                 r = gethostname_strict(&hostname);
                 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
-                        return r;
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to get hostname: %m");
 
                 hn = hostname;
         }
@@ -1513,9 +1520,9 @@ static int dhcp6_set_hostname(sd_dhcp6_client *client, Link *link) {
         r = sd_dhcp6_client_set_fqdn(client, hn);
         if (r == -EINVAL && hostname)
                 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
-                log_link_warning_errno(link, r, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
+                log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
         else if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set hostname: %m");
+                return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set hostname: %m");
 
         return 0;
 }
@@ -1571,7 +1578,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
         return 0;
 }
 
-int dhcp6_configure(Link *link) {
+static int dhcp6_configure(Link *link) {
         _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
         sd_dhcp6_option *vendor_option;
         sd_dhcp6_option *send_option;
@@ -1581,36 +1588,29 @@ int dhcp6_configure(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
-                return 0;
-
         if (link->dhcp6_client)
-                return -EBUSY;
-
-        r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
-        if (r <= 0)
-                return r;
+                return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv6 client is already configured.");
 
         r = sd_dhcp6_client_new(&client);
         if (r == -ENOMEM)
-                return log_oom();
+                return log_oom_debug();
         if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
+                return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
 
         r = sd_dhcp6_client_attach_event(client, link->manager->event, 0);
         if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to attach event: %m");
+                return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to attach event: %m");
 
         r = dhcp6_set_identifier(link, client);
         if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set identifier: %m");
+                return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set identifier: %m");
 
         ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options) {
                 r = sd_dhcp6_client_add_option(client, send_option);
                 if (r == -EEXIST)
                         continue;
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set option: %m");
         }
 
         r = dhcp6_set_hostname(client, link);
@@ -1619,18 +1619,18 @@ int dhcp6_configure(Link *link) {
 
         r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
         if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set ifindex: %m");
+                return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set ifindex: %m");
 
         if (link->network->dhcp6_rapid_commit) {
                 r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_RAPID_COMMIT);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for rapid commit: %m");
         }
 
         if (link->network->dhcp6_mudurl) {
                 r = sd_dhcp6_client_set_request_mud_url(client, link->network->dhcp6_mudurl);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
         }
 
         SET_FOREACH(request_options, link->network->dhcp6_request_options) {
@@ -1638,23 +1638,23 @@ int dhcp6_configure(Link *link) {
 
                 r = sd_dhcp6_client_set_request_option(client, option);
                 if (r == -EEXIST) {
-                        log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
+                        log_link_debug(link, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
                         continue;
                 }
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option);
         }
 
         if (link->network->dhcp6_user_class) {
                 r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set user class: %m");
         }
 
         if (link->network->dhcp6_vendor_class) {
                 r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor class: %m");
         }
 
         ORDERED_HASHMAP_FOREACH(vendor_option, link->network->dhcp6_client_send_vendor_options) {
@@ -1662,23 +1662,23 @@ int dhcp6_configure(Link *link) {
                 if (r == -EEXIST)
                         continue;
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor option: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set vendor option: %m");
         }
 
         r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
         if (r < 0)
-                return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
+                return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m");
 
         if (dhcp6_enable_prefix_delegation(link)) {
                 r = sd_dhcp6_client_set_prefix_delegation(client, true);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix delegation: %m");
         }
 
         if (link->network->dhcp6_pd_length > 0) {
                 r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m");
+                        return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set prefix hint: %m");
         }
 
         link->dhcp6_client = TAKE_PTR(client);
@@ -1716,6 +1716,60 @@ int dhcp6_update_mac(Link *link) {
         return 0;
 }
 
+int request_process_dhcp6_client(Request *req) {
+        Link *link;
+        int r;
+
+        assert(req);
+        assert(req->link);
+        assert(req->type == REQUEST_TYPE_DHCP6_CLIENT);
+
+        link = req->link;
+
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                return 0;
+
+        r = dhcp_configure_duid(link, link_get_dhcp6_duid(link));
+        if (r <= 0)
+                return r;
+
+        r = dhcp6_configure(link);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to configure DHCPv6 client: %m");
+
+        r = ndisc_start(link);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
+
+        r = dhcp6_start(link);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
+
+        log_link_debug(link, "DHCPv6 client is configured%s.",
+                       r > 0 ? ", acquiring DHCPv6 lease" : "");
+
+        return 1;
+}
+
+int link_request_dhcp6_client(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
+                return 0;
+
+        if (link->dhcp6_client)
+                return 0;
+
+        r = link_queue_request(link, REQUEST_TYPE_DHCP6_CLIENT, NULL, false, NULL, NULL, NULL);
+        if (r < 0)
+                return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv6 client: %m");
+
+        log_link_debug(link, "Requested configuring of the DHCPv6 client.");
+        return 0;
+}
+
 int link_serialize_dhcp6_client(Link *link, FILE *f) {
         _cleanup_free_ char *duid = NULL;
         uint32_t iaid;
index 82becb03217e18ad32f1210e79306764aee5735c..23612454d94e32315a8f14a1d93905a416835a98 100644 (file)
@@ -1,9 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#include "sd-dhcp6-client.h"
-
 #include "conf-parser.h"
+#include "in-addr-util.h"
 #include "macro.h"
 
 typedef enum DHCP6ClientStartMode {
@@ -15,7 +14,7 @@ typedef enum DHCP6ClientStartMode {
 } DHCP6ClientStartMode;
 
 typedef struct Link Link;
-typedef struct Manager Manager;
+typedef struct Request Request;
 
 typedef struct DHCP6DelegatedPrefix {
         struct in6_addr prefix;     /* Prefix assigned to the link */
@@ -29,12 +28,14 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
 bool link_dhcp6_with_address_enabled(Link *link);
 bool link_dhcp6_pd_is_enabled(Link *link);
 int dhcp6_pd_remove(Link *link);
-int dhcp6_configure(Link *link);
 int dhcp6_update_mac(Link *link);
 int dhcp6_start(Link *link);
 int dhcp6_request_information(Link *link, int ir);
 int dhcp6_request_prefix_delegation(Link *link);
 
+int request_process_dhcp6_client(Request *req);
+int link_request_dhcp6_client(Link *link);
+
 int link_serialize_dhcp6_client(Link *link, FILE *f);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
index 17fb932f81ac1d33fb4378fdfd32092306a063a6..6855189bcc3b2bf998b28be49408a95a7f73c438 100644 (file)
@@ -507,7 +507,7 @@ void link_check_ready(Link *link) {
             !link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
             !link->ipv4ll_address_configured)
                 /* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
-                return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
+                return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
 
         /* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
         if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
@@ -522,8 +522,8 @@ void link_check_ready(Link *link) {
                         /* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
                         return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
 
-                log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp6_routes:%s "
-                               "dhcp6_pd_addresses:%s dhcp6_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
+                log_link_debug(link, "%s(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s "
+                               "DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s",
                                __func__,
                                yes_no(link->dhcp4_configured),
                                yes_no(link->ipv4ll_address_configured),
@@ -650,12 +650,14 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
                 if (r < 0)
                         return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
 
-        } else if (link->ipv4ll) {
-                log_link_debug(link, "Acquiring IPv4 link-local address");
+                log_link_debug(link, "Acquiring DHCPv4 lease.");
 
+        } else if (link->ipv4ll) {
                 r = sd_ipv4ll_start(link->ipv4ll);
                 if (r < 0)
                         return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
+
+                log_link_debug(link, "Acquiring IPv4 link-local address.");
         }
 
         if (link->dhcp_server) {
@@ -690,6 +692,12 @@ static int link_acquire_dynamic_conf(Link *link) {
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
 
+        if (link->lldp) {
+                r = sd_lldp_start(link->lldp);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to start LLDP client: %m");
+        }
+
         return 0;
 }
 
@@ -975,8 +983,6 @@ static Link *link_drop(Link *link) {
 
         link_drop_from_master(link);
 
-        link_unref(set_remove(link->manager->links_requesting_uuid, link));
-
         (void) unlink(link->state_file);
         link_clean(link);
 
@@ -999,6 +1005,16 @@ static int link_drop_foreign_config(Link *link) {
         assert(link);
         assert(link->manager);
 
+        /* Drop foreign config, but ignore unmanaged, loopback, or critical interfaces. We do not want
+         * to remove loopback address or addresses used for root NFS. */
+
+        if (IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
+                return 0;
+        if (FLAGS_SET(link->flags, IFF_LOOPBACK))
+                return 0;
+        if (link->network->keep_configuration == KEEP_CONFIGURATION_YES)
+                return 0;
+
         r = link_drop_foreign_routes(link);
 
         k = link_drop_foreign_nexthops(link);
@@ -1127,11 +1143,11 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        r = dhcp4_configure(link);
+        r = link_request_dhcp4_client(link);
         if (r < 0)
                 return r;
 
-        r = dhcp6_configure(link);
+        r = link_request_dhcp6_client(link);
         if (r < 0)
                 return r;
 
@@ -1151,14 +1167,9 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        /* Drop foreign config, but ignore loopback or critical devices.
-         * We do not want to remove loopback address or addresses used for root NFS. */
-        if (!(link->flags & IFF_LOOPBACK) &&
-            link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
-                r = link_drop_foreign_config(link);
-                if (r < 0)
-                        return r;
-        }
+        r = link_drop_foreign_config(link);
+        if (r < 0)
+                return r;
 
         r = link_request_static_configs(link);
         if (r < 0)
@@ -1224,23 +1235,22 @@ static int link_get_network(Link *link, Network **ret) {
 }
 
 static int link_reconfigure_impl(Link *link, bool force) {
-        Network *network;
+        Network *network = NULL;
         int r;
 
         assert(link);
 
         r = link_get_network(link, &network);
-        if (r == -ENOENT) {
-                link_set_state(link, LINK_STATE_UNMANAGED);
-                return 0;
-        }
-        if (r < 0)
+        if (r < 0 && r != -ENOENT)
                 return r;
 
         if (link->network == network && !force)
                 return 0;
 
-        log_link_info(link, "Re-configuring with %s", network->filename);
+        if (network)
+                log_link_info(link, "Reconfiguring with %s.", network->filename);
+        else
+                log_link_info(link, "Unmanaging interface.");
 
         /* Dropping old .network file */
         r = link_stop_engines(link, false);
@@ -1253,17 +1263,14 @@ static int link_reconfigure_impl(Link *link, bool force) {
         if (r < 0)
                 return r;
 
-        if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
-                log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
-                r = link_drop_foreign_config(link);
-                if (r < 0)
-                        return r;
-        }
-
         link_free_carrier_maps(link);
         link_free_engines(link);
         link->network = network_unref(link->network);
-        link_unref(set_remove(link->manager->links_requesting_uuid, link));
+
+        if (!network) {
+                link_set_state(link, LINK_STATE_UNMANAGED);
+                return 0;
+        }
 
         /* Then, apply new .network file */
         link->network = network_ref(network);
@@ -1284,44 +1291,107 @@ static int link_reconfigure_impl(Link *link, bool force) {
         return 1;
 }
 
-static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
+static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) {
+        bool link_was_lower_up;
         int r;
 
+        assert(link);
+
+        link_was_lower_up = link->flags & IFF_LOWER_UP;
+
         r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
         if (r <= 0)
                 return r;
 
+        if (update_wifi && link_was_lower_up && link->flags & IFF_LOWER_UP) {
+                /* If the interface's L1 was not up, then wifi_get_info() is already called in
+                 * link_update_flags(). So, it is not necessary to re-call here. */
+                r = wifi_get_info(link);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return 0;
+                }
+        }
+
         r = link_reconfigure_impl(link, force);
-        if (r < 0)
+        if (r < 0) {
                 link_enter_failed(link);
+                return 0;
+        }
 
-        return 0;
+        return r;
 }
 
 static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        return link_reconfigure_handler_internal(rtnl, m, link, false);
+        return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ false);
 }
 
 static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
-        return link_reconfigure_handler_internal(rtnl, m, link, true);
+        return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true, /* update_wifi = */ false);
 }
 
-int link_reconfigure(Link *link, bool force) {
+static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
+        assert(link);
+
+        r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ true);
+        if (r != 0)
+                return r;
+
+        /* r == 0 means an error occurs, the link is unmanaged, or the matching network file is unchanged. */
+        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                return 0;
+
+        /* re-request static configs, and restart engines. */
+        r = link_stop_engines(link, false);
+        if (r < 0) {
+                link_enter_failed(link);
+                return 0;
+        }
+
+        r = link_acquire_dynamic_conf(link);
+        if (r < 0) {
+                link_enter_failed(link);
+                return 0;
+        }
+
+        r = link_request_static_configs(link);
+        if (r < 0) {
+                link_enter_failed(link);
+                return 0;
+        }
+
+        return 0;
+}
+
+static int link_reconfigure_internal(Link *link, link_netlink_message_handler_t callback) {
+        int r;
+
+        assert(link);
+        assert(callback);
+
         /* When link in pending or initialized state, then link_configure() will be called. To prevent
          * the function from being called multiple times simultaneously, refuse to reconfigure the
          * interface in these cases. */
         if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
                 return 0; /* 0 means no-op. */
 
-        r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
+        r = link_call_getlink(link, callback);
         if (r < 0)
                 return r;
 
         return 1; /* 1 means the interface will be reconfigured. */
 }
 
+int link_reconfigure(Link *link, bool force) {
+        return link_reconfigure_internal(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
+}
+
+int link_reconfigure_after_sleep(Link *link) {
+        return link_reconfigure_internal(link, link_reconfigure_after_sleep_handler);
+}
+
 static int link_initialized_and_synced(Link *link) {
         Network *network;
         int r;
@@ -1560,34 +1630,7 @@ static int link_carrier_lost(Link *link) {
         if (r < 0)
                 return r;
 
-        if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) {
-                log_link_debug(link, "State is %s, dropping foreign config", link_state_to_string(link->state));
-                r = link_drop_foreign_config(link);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int link_carrier_reset(Link *link) {
-        int r;
-
-        assert(link);
-
-        if (!link_has_carrier(link))
-                return 0;
-
-        r = link_carrier_lost(link);
-        if (r < 0)
-                return r;
-
-        r = link_carrier_gained(link);
-        if (r < 0)
-                return r;
-
-        log_link_info(link, "Reset carrier");
-        return 0;
+        return link_drop_foreign_config(link);
 }
 
 static int link_admin_state_up(Link *link) {
@@ -1943,10 +1986,6 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
                         return r;
         }
 
-        r = link_update_lldp(link);
-        if (r < 0)
-                return r;
-
         if (!had_carrier && link_has_carrier(link)) {
                 log_link_info(link, "Gained carrier");
 
index 4077ccaf09c5b99ba32b702834052873d826a128..79400dee2e9c1b22d30435bca75536ee2c82fc5a 100644 (file)
@@ -232,7 +232,6 @@ void link_check_ready(Link *link);
 
 void link_update_operstate(Link *link, bool also_update_bond_master);
 
-int link_carrier_reset(Link *link);
 bool link_has_carrier(Link *link);
 
 bool link_ipv6_enabled(Link *link);
@@ -247,6 +246,7 @@ const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
 
 int link_reconfigure(Link *link, bool force);
+int link_reconfigure_after_sleep(Link *link);
 
 int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
 int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
index c30cc36b51c0b48df6b629ca33206bebbd504e8c..57c8446adef0111f4bfde4f9ea3fbbf3c4c504cc 100644 (file)
@@ -103,38 +103,9 @@ int link_lldp_rx_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        r = link_update_lldp(link);
-        if (r < 0)
-                return r;
-
         return 0;
 }
 
-int link_update_lldp(Link *link) {
-        int r;
-
-        assert(link);
-
-        if (!link->lldp)
-                return 0;
-
-        if (link->flags & IFF_UP) {
-                r = sd_lldp_start(link->lldp);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Failed to start LLDP: %m");
-                if (r > 0)
-                        log_link_debug(link, "Started LLDP.");
-        } else {
-                r = sd_lldp_stop(link->lldp);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Failed to stop LLDP: %m");
-                if (r > 0)
-                        log_link_debug(link, "Stopped LLDP.");
-        }
-
-        return r;
-}
-
 int link_lldp_save(Link *link) {
         _cleanup_(unlink_and_freep) char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
index 49306eafd0ae04d6e24a9efdacf1fccb362612cf..22f6602bd0ffd8c5f853c6680e3e6a957ca0d228 100644 (file)
@@ -14,7 +14,6 @@ typedef enum LLDPMode {
 } LLDPMode;
 
 int link_lldp_rx_configure(Link *link);
-int link_update_lldp(Link *link);
 int link_lldp_save(Link *link);
 
 const char* lldp_mode_to_string(LLDPMode m) _const_;
index 374d27bef34cd2654ce025a5a087eca1658cdf41..e7aa804f096581e43308d574c740dc939c1b4c43 100644 (file)
@@ -59,9 +59,9 @@ static int manager_reset_all(Manager *m) {
         assert(m);
 
         HASHMAP_FOREACH(link, m->links_by_index) {
-                r = link_carrier_reset(link);
+                r = link_reconfigure_after_sleep(link);
                 if (r < 0) {
-                        log_link_warning_errno(link, r, "Could not reset carrier: %m");
+                        log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
                         link_enter_failed(link);
                 }
         }
@@ -103,7 +103,7 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
                 (void) manager_set_hostname(m, m->dynamic_hostname);
         if (m->dynamic_timezone)
                 (void) manager_set_timezone(m, m->dynamic_timezone);
-        if (!set_isempty(m->links_requesting_uuid))
+        if (m->product_uuid_requested)
                 (void) manager_request_product_uuid(m);
 
         return 0;
@@ -460,7 +460,6 @@ Manager* manager_free(Manager *m) {
         m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
 
         m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
-        m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
         m->links_by_name = hashmap_free(m->links_by_name);
         m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
         m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
index 4ee48f3468bf92b25ad582e97a062b4401876e98..4e789045380d5fb1e6dcfc7a28b4db628438c2de 100644 (file)
@@ -60,7 +60,6 @@ struct Manager {
         DUID duid_product_uuid;
         bool has_product_uuid;
         bool product_uuid_requested;
-        Set *links_requesting_uuid;
 
         char* dynamic_hostname;
         char* dynamic_timezone;
index 96a3ef9cb82ea04f5c560068a80cd042360982f4..f58edb8f3cae99673c8c625a298b91593f600a13 100644 (file)
 
 #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
 
+typedef enum IPv6TokenAddressGeneration {
+        IPV6_TOKEN_ADDRESS_GENERATION_NONE,
+        IPV6_TOKEN_ADDRESS_GENERATION_STATIC,
+        IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
+        _IPV6_TOKEN_ADDRESS_GENERATION_MAX,
+        _IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL,
+} IPv6TokenAddressGeneration;
+
+typedef struct IPv6Token {
+        IPv6TokenAddressGeneration address_generation_type;
+
+        uint8_t dad_counter;
+        struct in6_addr prefix;
+} IPv6Token;
+
 bool link_ipv6_accept_ra_enabled(Link *link) {
         assert(link);
 
@@ -619,7 +634,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         return 0;
 }
 
-static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
+static bool stable_private_address_is_valid(const struct in6_addr *addr) {
         assert(addr);
 
         /* According to rfc4291, generated address should not be in the following ranges. */
@@ -636,7 +651,7 @@ static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
         return true;
 }
 
-static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
+static int make_stable_private_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
         _cleanup_free_ struct in6_addr *addr = NULL;
         sd_id128_t secret_key;
         struct siphash state;
@@ -649,7 +664,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
 
         r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
         if (r < 0)
-                return log_error_errno(r, "Failed to generate key: %m");
+                return log_link_warning_errno(link, r, "Failed to generate key for IPv6 stable private address: %m");
 
         siphash24_init(&state, secret_key.bytes);
 
@@ -672,7 +687,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix,
         memcpy(addr->s6_addr, prefix->s6_addr, l);
         memcpy(addr->s6_addr + l, &rid, 16 - l);
 
-        if (!stableprivate_address_is_valid(addr)) {
+        if (!stable_private_address_is_valid(addr)) {
                 *ret = NULL;
                 return 0;
         }
@@ -704,7 +719,7 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address,
                          * only when the address generation algorithm produces an invalid address, and the loop
                          * may exit with an address which ends up being unusable due to duplication on the link. */
                         for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
-                                r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address);
+                                r = make_stable_private_address(link, address, prefixlen, j->dad_counter, &new_address);
                                 if (r < 0)
                                         return r;
                                 if (r > 0)
@@ -765,7 +780,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         assert(link);
         assert(rt);
 
-        r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
+        /* Do not use clock_boottime_or_monotonic() here, as the kernel internally manages cstamp and
+         * tstamp with jiffies, and it is not increased while the system is suspended. */
+        r = sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &time_now);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
 
@@ -1028,7 +1045,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
                 if (rdnss) {
                         rdnss->marked = false;
                         rdnss->router = router;
-                        rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
+                        rdnss->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
                         continue;
                 }
 
@@ -1039,7 +1056,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
                 *x = (NDiscRDNSS) {
                         .address = a[j],
                         .router = router,
-                        .valid_until = time_now + lifetime * USEC_PER_SEC,
+                        .valid_until = usec_add(time_now, lifetime * USEC_PER_SEC),
                 };
 
                 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
@@ -1126,12 +1143,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
                 if (dnssl) {
                         dnssl->marked = false;
                         dnssl->router = router;
-                        dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
+                        dnssl->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
                         continue;
                 }
 
                 s->router = router;
-                s->valid_until = time_now + lifetime * USEC_PER_SEC;
+                s->valid_until = usec_add(time_now, lifetime * USEC_PER_SEC);
 
                 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
                 if (r < 0)
@@ -1394,6 +1411,9 @@ int ndisc_start(Link *link) {
         if (!link->ndisc || !link->dhcp6_client)
                 return 0;
 
+        if (!link_has_carrier(link))
+                return 0;
+
         log_link_debug(link, "Discovering IPv6 routers");
 
         return sd_ndisc_start(link->ndisc);
@@ -1428,7 +1448,7 @@ void ndisc_flush(Link *link) {
         link->ndisc_dnssl = set_free(link->ndisc_dnssl);
 }
 
-int ipv6token_new(IPv6Token **ret) {
+static int ipv6token_new(IPv6Token **ret) {
         IPv6Token *p;
 
         p = new(IPv6Token, 1);
index 2ff9a8969d6bc8a0eb512825bb5897c1b131191c..2660794b5cac761073e829930533eecc97a57043 100644 (file)
@@ -7,16 +7,6 @@
 #include "networkd-route.h"
 #include "time-util.h"
 
-typedef struct IPv6Token IPv6Token;
-
-typedef enum IPv6TokenAddressGeneration {
-        IPV6_TOKEN_ADDRESS_GENERATION_NONE,
-        IPV6_TOKEN_ADDRESS_GENERATION_STATIC,
-        IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE,
-        _IPV6_TOKEN_ADDRESS_GENERATION_MAX,
-        _IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL,
-} IPv6TokenAddressGeneration;
-
 typedef enum IPv6AcceptRAStartDHCP6Client {
         IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
         IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
@@ -55,15 +45,6 @@ typedef struct NDiscDNSSL {
         /* The domain name follows immediately. */
 } NDiscDNSSL;
 
-struct IPv6Token {
-        IPv6TokenAddressGeneration address_generation_type;
-
-        uint8_t dad_counter;
-        struct in6_addr prefix;
-};
-
-int ipv6token_new(IPv6Token **ret);
-
 static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
         return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
 }
index 27a16f295173e75acc0eb0bb6c7cc73e7e23f7cc..7f2481997dadd792c39054d599afb27af8574e71 100644 (file)
@@ -5,6 +5,8 @@
 #include "networkd-bridge-fdb.h"
 #include "networkd-bridge-mdb.h"
 #include "networkd-dhcp-server.h"
+#include "networkd-dhcp4.h"
+#include "networkd-dhcp6.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-manager.h"
 #include "networkd-neighbor.h"
@@ -33,6 +35,8 @@ static void request_free_object(RequestType type, void *object) {
         case REQUEST_TYPE_CREATE_STACKED_NETDEV:
                 break;
         case REQUEST_TYPE_DHCP_SERVER:
+        case REQUEST_TYPE_DHCP4_CLIENT:
+        case REQUEST_TYPE_DHCP6_CLIENT:
                 break;
         case REQUEST_TYPE_IPV6_PROXY_NDP:
                 free(object);
@@ -112,7 +116,9 @@ static void request_hash_func(const Request *req, struct siphash *state) {
                 trivial_hash_func(req->object, state);
                 break;
         case REQUEST_TYPE_DHCP_SERVER:
-                /* This type does not have an object. */
+        case REQUEST_TYPE_DHCP4_CLIENT:
+        case REQUEST_TYPE_DHCP6_CLIENT:
+                /* These types do not have an object. */
                 break;
         case REQUEST_TYPE_IPV6_PROXY_NDP:
                 in6_addr_hash_func(req->ipv6_proxy_ndp, state);
@@ -170,6 +176,8 @@ static int request_compare_func(const struct Request *a, const struct Request *b
         case REQUEST_TYPE_CREATE_STACKED_NETDEV:
                 return trivial_compare_func(a->object, b->object);
         case REQUEST_TYPE_DHCP_SERVER:
+        case REQUEST_TYPE_DHCP4_CLIENT:
+        case REQUEST_TYPE_DHCP6_CLIENT:
                 return 0;
         case REQUEST_TYPE_IPV6_PROXY_NDP:
                 return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
@@ -218,12 +226,16 @@ int link_queue_request(
         assert(IN_SET(type,
                       REQUEST_TYPE_ACTIVATE_LINK,
                       REQUEST_TYPE_DHCP_SERVER,
+                      REQUEST_TYPE_DHCP4_CLIENT,
+                      REQUEST_TYPE_DHCP6_CLIENT,
                       REQUEST_TYPE_RADV,
                       REQUEST_TYPE_SET_LINK,
                       REQUEST_TYPE_UP_DOWN) ||
                object);
         assert(IN_SET(type,
                       REQUEST_TYPE_DHCP_SERVER,
+                      REQUEST_TYPE_DHCP4_CLIENT,
+                      REQUEST_TYPE_DHCP6_CLIENT,
                       REQUEST_TYPE_RADV) ||
                netlink_handler);
 
@@ -300,6 +312,12 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
                         case REQUEST_TYPE_DHCP_SERVER:
                                 r = request_process_dhcp_server(req);
                                 break;
+                        case REQUEST_TYPE_DHCP4_CLIENT:
+                                r = request_process_dhcp4_client(req);
+                                break;
+                        case REQUEST_TYPE_DHCP6_CLIENT:
+                                r = request_process_dhcp6_client(req);
+                                break;
                         case REQUEST_TYPE_IPV6_PROXY_NDP:
                                 r = request_process_ipv6_proxy_ndp_address(req);
                                 break;
index 85d2be7367d30192d1dba4e18c8ad4dfafe02949..1fdd07d60a3dbabbfef67fc6d54f3ea7b6df0f98 100644 (file)
@@ -28,6 +28,8 @@ typedef enum RequestType {
         REQUEST_TYPE_BRIDGE_MDB,
         REQUEST_TYPE_CREATE_STACKED_NETDEV,
         REQUEST_TYPE_DHCP_SERVER,
+        REQUEST_TYPE_DHCP4_CLIENT,
+        REQUEST_TYPE_DHCP6_CLIENT,
         REQUEST_TYPE_IPV6_PROXY_NDP,
         REQUEST_TYPE_NEIGHBOR,
         REQUEST_TYPE_NEXTHOP,
index 953a12b5724d58182e07faf5020ea6853fab97bd..afb3795f2fa8db5f48f71df50aeab474b55b5e59 100644 (file)
@@ -869,9 +869,9 @@ int link_request_radv(Link *link) {
 
         r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
         if (r < 0)
-                return log_link_warning_errno(link, r, "Failed to request IPv6 Router Advertisement engine: %m");
+                return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
 
-        log_link_debug(link, "IPv6 Router Advertisement engine is requested.");
+        log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
         return 0;
 }
 
index 4a0327a19dcbf7eec16847ac762027be501e97b8..d98914e8b817ea94e31182100f468d86b6b87a6d 100644 (file)
@@ -47,8 +47,8 @@ DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const D
         if (cname->key->type == DNS_TYPE_CNAME)
                 return dns_resource_key_new(key->class, key->type, cname->cname.name);
         else {
+                _cleanup_free_ char *destination = NULL;
                 DnsResourceKey *k;
-                char *destination = NULL;
 
                 r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
                 if (r < 0)
@@ -58,8 +58,9 @@ DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const D
 
                 k = dns_resource_key_new_consume(key->class, key->type, destination);
                 if (!k)
-                        return mfree(destination);
+                        return NULL;
 
+                TAKE_PTR(destination);
                 return k;
         }
 }
index cec2c24151619eaf1c65e6df20e365002114bb19..aaabc92486ad65ac0488413c03415965423f33c4 100644 (file)
@@ -585,7 +585,7 @@ static int dns_stub_send_reply(
                         DNS_PACKET_RD(q->request_packet),
                         !!q->request_packet->opt,
                         edns0_do,
-                        DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q),
+                        (DNS_PACKET_AD(q->request_packet) || DNS_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q),
                         DNS_PACKET_CD(q->request_packet),
                         q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
                         dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra);
@@ -627,7 +627,7 @@ static int dns_stub_send_failure(
                         DNS_PACKET_RD(p),
                         !!p->opt,
                         DNS_PACKET_DO(p),
-                        DNS_PACKET_AD(p) && authenticated,
+                        (DNS_PACKET_AD(p) || DNS_PACKET_DO(p)) && authenticated,
                         DNS_PACKET_CD(p),
                         l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
                         dns_packet_has_nsid_request(p) > 0 && !l);
index b31cdd679ba56ab2c7e4be1c9a8e8f753f11a683..fee5bd1c95fbdedcc8ae04ce4b04209415a90e00 100644 (file)
@@ -215,13 +215,14 @@ int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line
 }
 
 int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
+        _cleanup_(utxent_cleanup) bool utmpx = false;
         struct utmpx lookup = {
                 .ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
         }, store, store_wtmp, *found;
 
         assert(id);
 
-        setutxent();
+        utmpx = utxent_start();
 
         /* Copy the whole string if it fits, or just the suffix without the terminating NUL. */
         copy_suffix(store.ut_id, sizeof(store.ut_id), id);
@@ -339,6 +340,7 @@ int utmp_wall(
         bool (*match_tty)(const char *tty, void *userdata),
         void *userdata) {
 
+        _cleanup_(utxent_cleanup) bool utmpx = false;
         _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
         struct utmpx *u;
         int r;
@@ -367,7 +369,7 @@ int utmp_wall(
                      message) < 0)
                 return -ENOMEM;
 
-        setutxent();
+        utmpx = utxent_start();
 
         r = 0;
 
index eb285efe94dfeed01926faf7b489db123a80559d..b9445cf0a9dfbf01922e61f4c9fc36e2f6551336 100644 (file)
@@ -81,6 +81,9 @@ _SD_BEGIN_DECLARATIONS;
 #define SD_MESSAGE_SHUTDOWN               SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
 #define SD_MESSAGE_SHUTDOWN_STR           SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
 
+#define SD_MESSAGE_FACTORY_RESET          SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
+#define SD_MESSAGE_FACTORY_RESET_STR      SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
+
 /* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover
  * SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with
  * SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
index b29c0d78440f0572c459870e4b9a2acb3ea639d6..8b7d46bee3f8d4b9aead3c77c5d8a551cde55439 100644 (file)
@@ -97,7 +97,7 @@ int main(int argc, char *argv[]) {
         /* The simple tests succeeded. Now let's try full unit-based use-case. */
 
         assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         assert_se(u = unit_new(m, sizeof(Service)));
         assert_se(unit_add_name(u, "foo.service") == 0);
index a6f8eb6f4ac612f36193135b9ef9c9d221a05e47..bbf3916872228000c0180f72927c87d82704656f 100644 (file)
@@ -304,7 +304,7 @@ int main(int argc, char *argv[]) {
         assert_se(runtime_dir = setup_fake_runtime_dir());
 
         assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         assert_se(test_bpf_cgroup_programs(m,
                                 "single_prog.service", single_prog, ELEMENTSOF(single_prog)) >= 0);
index 19e159b9ff1c892105576a33732a962f46df7804..184b393dd51d36df04464075fdb067909a9d925e 100644 (file)
@@ -60,7 +60,7 @@ static int test_cgroup_mask(void) {
                 m->default_tasks_accounting = false;
         m->default_tasks_max = TASKS_MAX_UNSET;
 
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         /* Load units and verify hierarchy. */
         assert_se(manager_load_startable_unit_or_warn(m, "parent.slice", NULL, &parent) >= 0);
index 225d138e41563e281400a0c0a079fb4e0c7d2b43..0fae2f64cb2abc5843676e75fd434cf3a2e101e9 100644 (file)
@@ -33,7 +33,7 @@ static int test_default_memory_low(void) {
         }
 
         assert_se(r >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         /* dml.slice has DefaultMemoryLow=50. Beyond that, individual subhierarchies look like this:
          *
index 6dc16193d3768fb79ab0cb5b9721f9bf94c54dcb..880af36fb5237cfa578d8cccb570be61630f8c58 100644 (file)
@@ -95,7 +95,7 @@ int main(int argc, char *argv[]) {
         if (manager_errno_skip_test(r))
                 return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         printf("Load1:\n");
         assert_se(manager_load_startable_unit_or_warn(m, "a.service", NULL, &a) >= 0);
index 125e0bbf4f75c781ae5aaaef7dfe3826558879f7..a0481f119440fc0a53c38a907629aa0d62f9961a 100644 (file)
@@ -844,7 +844,7 @@ static int run_tests(UnitFileScope scope, const test_entry tests[], char **patte
         if (manager_errno_skip_test(r))
                 return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         for (const test_entry *test = tests; test->f; test++)
                 if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
index b41a8abf7bc552741a938ea3a484512af0315e6a..e0ba99199c9dca5b78e9df93067de97baeb23d72 100644 (file)
@@ -104,7 +104,7 @@ static void test_config_parse_exec(void) {
         }
 
         assert_se(r >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         assert_se(u = unit_new(m, sizeof(Service)));
 
@@ -448,7 +448,7 @@ static void test_config_parse_log_extra_fields(void) {
         }
 
         assert_se(r >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         assert_se(u = unit_new(m, sizeof(Service)));
 
index ceea7a62f5155b8cc3c4b3735f7bdce9bf9a584a..1a0fda5d1af90bae9ba32ef4d3d739c69d3c59b9 100644 (file)
@@ -204,12 +204,12 @@ static void test_find_executable_full(void) {
 
         log_info("/* %s */", __func__);
 
-        assert_se(find_executable_full("sh", true, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
 
-        assert_se(find_executable_full("sh", false, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
@@ -221,12 +221,12 @@ static void test_find_executable_full(void) {
 
         assert_se(unsetenv("PATH") == 0);
 
-        assert_se(find_executable_full("sh", true, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
 
-        assert_se(find_executable_full("sh", false, &p, NULL) == 0);
+        assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
         puts(p);
         assert_se(streq(basename(p), "sh"));
         free(p);
@@ -277,7 +277,7 @@ static void test_find_executable_exec_one(const char *path) {
         pid_t pid;
         int r;
 
-        r = find_executable_full(path, false, &t, &fd);
+        r = find_executable_full(path, NULL, false, &t, &fd);
 
         log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd);
 
index 490fb136a7604b6185371f36587297a87d9390e0..04cb4fa37c710363615023ea33057ec982c0cc73 100644 (file)
@@ -38,7 +38,7 @@ static int setup_test(Manager **m) {
         if (manager_errno_skip_test(r))
                 return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
-        assert_se(manager_startup(tmp, NULL, NULL) >= 0);
+        assert_se(manager_startup(tmp, NULL, NULL, NULL) >= 0);
 
         STRV_FOREACH(test_path, tests_path) {
                 _cleanup_free_ char *p = NULL;
index 1f125b1d1e23035b0d90921a187923961e25cfa9..35f7be491ab973001b5393af2a1fd06daa988285 100644 (file)
@@ -34,7 +34,7 @@ int main(int argc, char *argv[]) {
         if (manager_errno_skip_test(r))
                 return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         /* load idle ok */
         assert_se(manager_load_startable_unit_or_warn(m, "sched_idle_ok.service", NULL, &idle_ok) >= 0);
index 989172eee3b9569686ff5dc9c5df9b206e2dc557..ecad86baebff0738463de64e45b7c6af69251b1b 100644 (file)
@@ -138,7 +138,7 @@ int main(int argc, char *argv[]) {
         assert_se(runtime_dir = setup_fake_runtime_dir());
 
         assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0);
         assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("ipv6:2001-2002"), STRV_MAKE("any")) >= 0);
index 4afc46f10f04a58e55a7d0800b5454662f83753d..885ed802d40d65b72939805fd99734896a45e7f9 100644 (file)
@@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
         assert_se(runtime_dir = setup_fake_runtime_dir());
 
         assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
-        assert_se(manager_startup(m, NULL, NULL) >= 0);
+        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
 
         assert_se(a = unit_new(m, sizeof(Service)));
         assert_se(unit_add_name(a, "a.service") >= 0);
index 556a2e9ba866040f5c67b84e164099c83e2abe9d..731dea12e3a54512338365f8013afab993b625d1 100644 (file)
@@ -25,3 +25,4 @@ Time.RootDistanceMaxSec,             config_parse_sec,     0,               offs
 Time.PollIntervalMinSec,             config_parse_sec,     0,               offsetof(Manager, poll_interval_min_usec)
 Time.PollIntervalMaxSec,             config_parse_sec,     0,               offsetof(Manager, poll_interval_max_usec)
 Time.ConnectionRetrySec,             config_parse_sec,     0,               offsetof(Manager, connection_retry_usec)
+Time.SaveIntervalSec,                config_parse_sec,     0,               offsetof(Manager, save_time_interval_usec)
index cb5d42b1d3ff1c7e1fdc34fcbe021e403c31bf3c..1c284f31e3ee6baf85043eaecc4397a1f1aef395 100644 (file)
@@ -59,6 +59,7 @@ static int manager_arm_timer(Manager *m, usec_t next);
 static int manager_clock_watch_setup(Manager *m);
 static int manager_listen_setup(Manager *m);
 static void manager_listen_stop(Manager *m);
+static int manager_save_time_and_rearm(Manager *m);
 
 static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
         return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
@@ -303,8 +304,11 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
         if (r < 0)
                 return -errno;
 
+        r = manager_save_time_and_rearm(m);
+        if (r < 0)
+                return r;
+
         /* If touch fails, there isn't much we can do. Maybe it'll work next time. */
-        (void) touch("/var/lib/systemd/timesync/clock");
         (void) touch("/run/systemd/timesync/synchronized");
 
         m->drift_freq = tmx.freq;
@@ -591,7 +595,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                   m->poll_interval_usec / USEC_PER_SEC);
 
         if (!spike) {
-                m->sync = true;
                 r = manager_adjust_clock(m, offset, leap_sec);
                 if (r < 0)
                         log_error_errno(r, "Failed to call clock_adjtime(): %m");
@@ -942,6 +945,8 @@ Manager* manager_free(Manager *m) {
         sd_event_source_unref(m->network_event_source);
         sd_network_monitor_unref(m->network_monitor);
 
+        sd_event_source_unref(m->event_save_time);
+
         sd_resolve_unref(m->resolve);
         sd_event_unref(m->event);
 
@@ -1104,6 +1109,8 @@ int manager_new(Manager **ret) {
 
         m->ratelimit = (RateLimit) { RATELIMIT_INTERVAL_USEC, RATELIMIT_BURST };
 
+        m->save_time_interval_usec = DEFAULT_SAVE_TIME_INTERVAL_USEC;
+
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -1131,3 +1138,60 @@ int manager_new(Manager **ret) {
 
         return 0;
 }
+
+static int manager_save_time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+        Manager *m = userdata;
+
+        assert(m);
+
+        (void) manager_save_time_and_rearm(m);
+        return 0;
+}
+
+int manager_setup_save_time_event(Manager *m) {
+        int r;
+
+        assert(m);
+        assert(!m->event_save_time);
+
+        if (m->save_time_interval_usec == USEC_INFINITY)
+                return 0;
+
+        /* NB: we'll accumulate scheduling latencies here, but this doesn't matter */
+        r = sd_event_add_time_relative(
+                        m->event, &m->event_save_time,
+                        clock_boottime_or_monotonic(),
+                        m->save_time_interval_usec,
+                        10 * USEC_PER_SEC,
+                        manager_save_time_handler, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add save time event: %m");
+
+        (void) sd_event_source_set_description(m->event_save_time, "save-time");
+
+        return 0;
+}
+
+static int manager_save_time_and_rearm(Manager *m) {
+        int r;
+
+        assert(m);
+
+        r = touch(CLOCK_FILE);
+        if (r < 0)
+                log_debug_errno(r, "Failed to update " CLOCK_FILE ", ignoring: %m");
+
+        m->save_on_exit = true;
+
+        if (m->save_time_interval_usec != USEC_INFINITY) {
+                r = sd_event_source_set_time_relative(m->event_save_time, m->save_time_interval_usec);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to rearm save time event: %m");
+
+                r = sd_event_source_set_enabled(m->event_save_time, SD_EVENT_ONESHOT);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to enable save time event: %m");
+        }
+
+        return 0;
+}
index 4aa7575a8029f877d39d424be12148609dfc3107..aceb0098cef37cc26cb5e7218d0af538de44075f 100644 (file)
@@ -27,7 +27,12 @@ typedef struct Manager Manager;
 #define NTP_RETRY_INTERVAL_MIN_USEC     (15 * USEC_PER_SEC)
 #define NTP_RETRY_INTERVAL_MAX_USEC     (6 * 60 * USEC_PER_SEC) /* 6 minutes */
 
-#define DEFAULT_CONNECTION_RETRY_USEC (30*USEC_PER_SEC)
+#define DEFAULT_CONNECTION_RETRY_USEC   (30 * USEC_PER_SEC)
+
+#define DEFAULT_SAVE_TIME_INTERVAL_USEC (60 * USEC_PER_SEC)
+
+#define STATE_DIR   "/var/lib/systemd/timesync"
+#define CLOCK_FILE  STATE_DIR "/clock"
 
 struct Manager {
         sd_bus *bus;
@@ -83,7 +88,6 @@ struct Manager {
 
         /* last change */
         bool jumped;
-        bool sync;
         int64_t drift_freq;
 
         /* watch for time changes */
@@ -100,6 +104,11 @@ struct Manager {
         struct ntp_msg ntpmsg;
         struct timespec origin_time, dest_time;
         bool spike;
+
+        /* save time event */
+        sd_event_source *event_save_time;
+        usec_t save_time_interval_usec;
+        bool save_on_exit;
 };
 
 int manager_new(Manager **ret);
@@ -113,3 +122,5 @@ void manager_flush_server_names(Manager *m, ServerType t);
 
 int manager_connect(Manager *m);
 void manager_disconnect(Manager *m);
+
+int manager_setup_save_time_event(Manager *m);
index e6a2b06687346460d526c77be00a324f8613a246..179562696d2dd4206566799a7de91c1fe13488c9 100644 (file)
@@ -21,9 +21,6 @@
 #include "timesyncd-manager.h"
 #include "user-util.h"
 
-#define STATE_DIR   "/var/lib/systemd/timesync"
-#define CLOCK_FILE  STATE_DIR "/clock"
-
 static int load_clock_timestamp(uid_t uid, gid_t gid) {
         _cleanup_close_ int fd = -1;
         usec_t min = TIME_EPOCH * USEC_PER_SEC;
@@ -155,6 +152,10 @@ static int run(int argc, char *argv[]) {
                                       "STATUS=Daemon is running",
                                       NOTIFY_STOPPING);
 
+        r = manager_setup_save_time_event(m);
+        if (r < 0)
+                return r;
+
         if (network_is_online()) {
                 r = manager_connect(m);
                 if (r < 0)
@@ -166,10 +167,10 @@ static int run(int argc, char *argv[]) {
                 return log_error_errno(r, "Failed to run event loop: %m");
 
         /* if we got an authoritative time, store it in the file system */
-        if (m->sync) {
+        if (m->save_on_exit) {
                 r = touch(CLOCK_FILE);
                 if (r < 0)
-                        log_debug_errno(r, "Failed to touch %s, ignoring: %m", CLOCK_FILE);
+                        log_debug_errno(r, "Failed to touch " CLOCK_FILE ", ignoring: %m");
         }
 
         return 0;
index d5f29e1598cb4ecba393b20d5645c7907d95ff57..df02cb5bd60bcddd4774685b68a39aafa10ff7ca 100644 (file)
@@ -18,3 +18,4 @@
 #RootDistanceMaxSec=5
 #PollIntervalMinSec=32
 #PollIntervalMaxSec=2048
+#SaveIntervalSec=60
index 3d563547190cebce00464a44d6ead24a4b8fa40e..00279ba3d87dd30715d049024fbde829f0be173b 100644 (file)
 /* wire protocol magic must match */
 #define UDEV_CTRL_MAGIC                                0xdead1dea
 
-struct udev_ctrl_msg_wire {
+typedef struct UdevCtrlMessageWire {
         char version[16];
         unsigned magic;
-        enum udev_ctrl_msg_type type;
-        union udev_ctrl_msg_value value;
-};
+        UdevCtrlMessageType type;
+        UdevCtrlMessageValue value;
+} UdevCtrlMessageWire;
 
-struct udev_ctrl {
+struct UdevCtrl {
         unsigned n_ref;
         int sock;
         int sock_connect;
@@ -47,9 +47,9 @@ struct udev_ctrl {
         void *userdata;
 };
 
-int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
+int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) {
         _cleanup_close_ int sock = -1;
-        struct udev_ctrl *uctrl;
+        UdevCtrl *uctrl;
 
         assert(ret);
 
@@ -59,11 +59,11 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
                         return log_error_errno(errno, "Failed to create socket: %m");
         }
 
-        uctrl = new(struct udev_ctrl, 1);
+        uctrl = new(UdevCtrl, 1);
         if (!uctrl)
                 return -ENOMEM;
 
-        *uctrl = (struct udev_ctrl) {
+        *uctrl = (UdevCtrl) {
                 .n_ref = 1,
                 .sock = fd >= 0 ? fd : TAKE_FD(sock),
                 .sock_connect = -1,
@@ -81,7 +81,7 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
         return 0;
 }
 
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
+int udev_ctrl_enable_receiving(UdevCtrl *uctrl) {
         int r;
 
         assert(uctrl);
@@ -107,7 +107,7 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
         return 0;
 }
 
-static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
+static void udev_ctrl_disconnect(UdevCtrl *uctrl) {
         if (!uctrl)
                 return;
 
@@ -115,7 +115,7 @@ static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
         uctrl->sock_connect = safe_close(uctrl->sock_connect);
 }
 
-static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
+static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) {
         assert(uctrl);
 
         udev_ctrl_disconnect(uctrl);
@@ -127,9 +127,9 @@ static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
         return mfree(uctrl);
 }
 
-DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
+DEFINE_TRIVIAL_REF_UNREF_FUNC(UdevCtrl, udev_ctrl, udev_ctrl_free);
 
-int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
+int udev_ctrl_cleanup(UdevCtrl *uctrl) {
         if (!uctrl)
                 return 0;
         if (uctrl->cleanup_socket)
@@ -137,7 +137,7 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
         return 0;
 }
 
-int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
+int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event) {
         int r;
 
         assert_return(uctrl, -EINVAL);
@@ -154,25 +154,25 @@ int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
         return 0;
 }
 
-sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) {
+sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl) {
         assert(uctrl);
 
         return uctrl->event_source;
 }
 
-static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) {
+static void udev_ctrl_disconnect_and_listen_again(UdevCtrl *uctrl) {
         udev_ctrl_disconnect(uctrl);
         udev_ctrl_unref(uctrl);
         (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON);
         /* We don't return NULL here because uctrl is not freed */
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct udev_ctrl*, udev_ctrl_disconnect_and_listen_again, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UdevCtrl*, udev_ctrl_disconnect_and_listen_again, NULL);
 
 static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
-        struct udev_ctrl_msg_wire msg_wire;
-        struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
+        _cleanup_(udev_ctrl_disconnect_and_listen_againp) UdevCtrl *uctrl = NULL;
+        UdevCtrlMessageWire msg_wire;
+        struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(UdevCtrlMessageWire));
         CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
         struct msghdr smsg = {
                 .msg_iov = &iov,
@@ -235,7 +235,7 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32
 }
 
 static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        struct udev_ctrl *uctrl = userdata;
+        UdevCtrl *uctrl = userdata;
         _cleanup_close_ int sock = -1;
         struct ucred ucred;
         int r;
@@ -282,7 +282,7 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents,
         return 0;
 }
 
-int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
+int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
         int r;
 
         assert(uctrl);
@@ -309,8 +309,8 @@ int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void
         return 0;
 }
 
-int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) {
-        struct udev_ctrl_msg_wire ctrl_msg_wire = {
+int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf) {
+        UdevCtrlMessageWire ctrl_msg_wire = {
                 .version = "udev-" STRINGIFY(PROJECT_VERSION),
                 .magic = UDEV_CTRL_MAGIC,
                 .type = type,
@@ -339,7 +339,7 @@ int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int in
         return 0;
 }
 
-int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
+int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout) {
         _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
         int r;
 
index 680fbf7bff1de84d4712f63e95ca358198a13200..ca80c2aa4e0d96b327288c79070a2e6f0b3e95f3 100644 (file)
@@ -6,9 +6,9 @@
 #include "macro.h"
 #include "time-util.h"
 
-struct udev_ctrl;
+typedef struct UdevCtrl UdevCtrl;
 
-enum udev_ctrl_msg_type {
+typedef enum UdevCtrlMessageType {
         _UDEV_CTRL_END_MESSAGES,
         UDEV_CTRL_SET_LOG_LEVEL,
         UDEV_CTRL_STOP_EXEC_QUEUE,
@@ -18,62 +18,62 @@ enum udev_ctrl_msg_type {
         UDEV_CTRL_SET_CHILDREN_MAX,
         UDEV_CTRL_PING,
         UDEV_CTRL_EXIT,
-};
+} UdevCtrlMessageType;
 
-union udev_ctrl_msg_value {
+typedef union UdevCtrlMessageValue {
         int intval;
         char buf[256];
-};
+} UdevCtrlMessageValue;
 
-typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type,
-                                   const union udev_ctrl_msg_value *value, void *userdata);
+typedef int (*udev_ctrl_handler_t)(UdevCtrl *udev_ctrl, UdevCtrlMessageType type,
+                                   const UdevCtrlMessageValue *value, void *userdata);
 
-int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd);
-static inline int udev_ctrl_new(struct udev_ctrl **ret) {
+int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd);
+static inline int udev_ctrl_new(UdevCtrl **ret) {
         return udev_ctrl_new_from_fd(ret, -1);
 }
 
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
-struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
-struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
-int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
-int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event);
-int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
-sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl);
+int udev_ctrl_enable_receiving(UdevCtrl *uctrl);
+UdevCtrl *udev_ctrl_ref(UdevCtrl *uctrl);
+UdevCtrl *udev_ctrl_unref(UdevCtrl *uctrl);
+int udev_ctrl_cleanup(UdevCtrl *uctrl);
+int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event);
+int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
+sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl);
 
-int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout);
+int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout);
 
-int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf);
-static inline int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority) {
+int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf);
+static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
 }
 
-static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) {
+static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
 }
 
-static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) {
+static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
 }
 
-static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) {
+static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
 }
 
-static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) {
+static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
 }
 
-static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) {
+static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
 }
 
-static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) {
+static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
 }
 
-static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) {
+static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) {
         return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref);
index d050134aef5df0da20075c759ed08638da179738..cb7de261d5aa2621e547423b75efb05ff831ebdd 100644 (file)
@@ -1154,7 +1154,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) {
                 if (!FLAGS_SET(line->type, LINE_HAS_GOTO))
                         continue;
 
-                LIST_FOREACH_AFTER(rule_lines, i, line)
+                LIST_FOREACH(rule_lines, i, line->rule_lines_next)
                         if (streq_ptr(i->label, line->goto_label)) {
                                 line->goto_line = i;
                                 break;
index 20820dd6472388eecab889dfac83620f658dc087..06c61e5c07c68bdd9dcdd7bce0ed143e8919afc5 100644 (file)
@@ -48,7 +48,7 @@ static int help(void) {
 }
 
 int control_main(int argc, char *argv[], void *userdata) {
-        _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
+        _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
         usec_t timeout = 60 * USEC_PER_SEC;
         int c, r;
 
index 84b4f9ca45887a31bb1f08a6b2ca411a0a69da9c..6da9439bd28af29ae3fed7afe94b55d6b165ad39 100644 (file)
@@ -176,7 +176,7 @@ int settle_main(int argc, char *argv[], void *userdata) {
 
         /* guarantee that the udev daemon isn't pre-processing */
         if (getuid() == 0) {
-                _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
+                _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
 
                 if (udev_ctrl_new(&uctrl) >= 0) {
                         r = udev_ctrl_send_ping(uctrl);
index 8acf3d9b118902db1ebc71d00dab6ad769cdee13..a24073fb734104857b247c727891aa7ed75bc6f6 100644 (file)
@@ -421,7 +421,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
         }
 
         if (ping) {
-                _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
+                _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
 
                 r = udev_ctrl_new(&uctrl);
                 if (r < 0)
index 5a4657de14a81c6bb904d825f7fc48ca31bde6ef..4df08f21c5c66bbc4142b01ec6ba52cd3de2486c 100644 (file)
@@ -77,10 +77,13 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
 static int arg_timeout_signal = SIGKILL;
 static bool arg_blockdev_read_only = false;
 
+typedef struct Event Event;
+typedef struct Worker Worker;
+
 typedef struct Manager {
         sd_event *event;
         Hashmap *workers;
-        LIST_HEAD(struct event, events);
+        LIST_HEAD(Event, events);
         const char *cgroup;
         pid_t pid; /* the process that originally allocated the manager object */
         int log_level;
@@ -91,7 +94,7 @@ typedef struct Manager {
         sd_netlink *rtnl;
 
         sd_device_monitor *monitor;
-        struct udev_ctrl *ctrl;
+        UdevCtrl *ctrl;
         int worker_watch[2];
 
         /* used by udev-watch */
@@ -106,54 +109,52 @@ typedef struct Manager {
         bool exit;
 } Manager;
 
-enum event_state {
+typedef enum EventState {
         EVENT_UNDEF,
         EVENT_QUEUED,
         EVENT_RUNNING,
-};
+} EventState;
 
-struct event {
+typedef struct Event {
         Manager *manager;
-        struct worker *worker;
-        enum event_state state;
+        Worker *worker;
+        EventState state;
 
         sd_device *dev;
         sd_device *dev_kernel; /* clone of originally received device */
 
         uint64_t seqnum;
-        uint64_t delaying_seqnum;
+        uint64_t blocker_seqnum;
 
         sd_event_source *timeout_warning_event;
         sd_event_source *timeout_event;
 
-        LIST_FIELDS(struct event, event);
-};
-
-static void event_queue_cleanup(Manager *manager, enum event_state type);
+        LIST_FIELDS(Event, event);
+} Event;
 
-enum worker_state {
+typedef enum WorkerState {
         WORKER_UNDEF,
         WORKER_RUNNING,
         WORKER_IDLE,
         WORKER_KILLED,
         WORKER_KILLING,
-};
+} WorkerState;
 
-struct worker {
+typedef struct Worker {
         Manager *manager;
         pid_t pid;
         sd_device_monitor *monitor;
-        enum worker_state state;
-        struct event *event;
-};
+        WorkerState state;
+        Event *event;
+} Worker;
 
 /* passed from worker to main process */
-struct worker_message {
-};
+typedef struct WorkerMessage {
+} WorkerMessage;
 
-static void event_free(struct event *event) {
+static Event *event_free(Event *event) {
         if (!event)
-                return;
+                return NULL;
 
         assert(event->manager);
 
@@ -170,13 +171,24 @@ static void event_free(struct event *event) {
         /* only clean up the queue from the process that created it */
         if (LIST_IS_EMPTY(event->manager->events) &&
             event->manager->pid == getpid_cached())
-                if (unlink("/run/udev/queue") < 0)
-                        log_warning_errno(errno, "Failed to unlink /run/udev/queue: %m");
+                if (unlink("/run/udev/queue") < 0 && errno != ENOENT)
+                        log_warning_errno(errno, "Failed to unlink /run/udev/queue, ignoring: %m");
 
-        free(event);
+        return mfree(event);
 }
 
-static struct worker* worker_free(struct worker *worker) {
+static void event_queue_cleanup(Manager *manager, EventState match_state) {
+        Event *event, *tmp;
+
+        LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
+                if (match_state != EVENT_UNDEF && match_state != event->state)
+                        continue;
+
+                event_free(event);
+        }
+}
+
+static Worker *worker_free(Worker *worker) {
         if (!worker)
                 return NULL;
 
@@ -189,11 +201,52 @@ static struct worker* worker_free(struct worker *worker) {
         return mfree(worker);
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free);
-DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, struct worker, worker_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Worker*, worker_free);
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, Worker, worker_free);
 
-static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
-        _cleanup_(worker_freep) struct worker *worker = NULL;
+static void manager_clear_for_worker(Manager *manager) {
+        assert(manager);
+
+        manager->inotify_event = sd_event_source_unref(manager->inotify_event);
+        manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event);
+
+        manager->event = sd_event_unref(manager->event);
+
+        manager->workers = hashmap_free(manager->workers);
+        event_queue_cleanup(manager, EVENT_UNDEF);
+
+        manager->monitor = sd_device_monitor_unref(manager->monitor);
+        manager->ctrl = udev_ctrl_unref(manager->ctrl);
+
+        manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
+}
+
+static Manager* manager_free(Manager *manager) {
+        if (!manager)
+                return NULL;
+
+        udev_builtin_exit();
+
+        if (manager->pid == getpid_cached())
+                udev_ctrl_cleanup(manager->ctrl);
+
+        manager_clear_for_worker(manager);
+
+        sd_netlink_unref(manager->rtnl);
+
+        hashmap_free_free_free(manager->properties);
+        udev_rules_free(manager->rules);
+
+        safe_close(manager->inotify_fd);
+        safe_close_pair(manager->worker_watch);
+
+        return mfree(manager);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+
+static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
+        _cleanup_(worker_freep) Worker *worker = NULL;
         int r;
 
         assert(ret);
@@ -204,11 +257,11 @@ static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *
         /* close monitor, but keep address around */
         device_monitor_disconnect(worker_monitor);
 
-        worker = new(struct worker, 1);
+        worker = new(Worker, 1);
         if (!worker)
                 return -ENOMEM;
 
-        *worker = (struct worker) {
+        *worker = (Worker) {
                 .manager = manager,
                 .monitor = sd_device_monitor_ref(worker_monitor),
                 .pid = pid,
@@ -223,99 +276,78 @@ static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *
         return 0;
 }
 
-static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
-        struct event *event = userdata;
-
-        assert(event);
-        assert(event->worker);
-
-        kill_and_sigcont(event->worker->pid, arg_timeout_signal);
-        event->worker->state = WORKER_KILLED;
-
-        log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
-
-        return 1;
-}
+static void manager_kill_workers(Manager *manager, bool force) {
+        Worker *worker;
 
-static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
-        struct event *event = userdata;
+        assert(manager);
 
-        assert(event);
-        assert(event->worker);
+        HASHMAP_FOREACH(worker, manager->workers) {
+                if (worker->state == WORKER_KILLED)
+                        continue;
 
-        log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
+                if (worker->state == WORKER_RUNNING && !force) {
+                        worker->state = WORKER_KILLING;
+                        continue;
+                }
 
-        return 1;
+                worker->state = WORKER_KILLED;
+                (void) kill(worker->pid, SIGTERM);
+        }
 }
 
-static void worker_attach_event(struct worker *worker, struct event *event) {
-        sd_event *e;
-
-        assert(worker);
-        assert(worker->manager);
-        assert(event);
-        assert(!event->worker);
-        assert(!worker->event);
-
-        worker->state = WORKER_RUNNING;
-        worker->event = event;
-        event->state = EVENT_RUNNING;
-        event->worker = worker;
-
-        e = worker->manager->event;
+static void manager_exit(Manager *manager) {
+        assert(manager);
 
-        (void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
-                                          udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC,
-                                          on_event_timeout_warning, event);
+        manager->exit = true;
 
-        (void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
-                                          arg_event_timeout_usec, USEC_PER_SEC,
-                                          on_event_timeout, event);
-}
+        sd_notify(false,
+                  "STOPPING=1\n"
+                  "STATUS=Starting shutdown...");
 
-static void manager_clear_for_worker(Manager *manager) {
-        assert(manager);
+        /* close sources of new events and discard buffered events */
+        manager->ctrl = udev_ctrl_unref(manager->ctrl);
 
         manager->inotify_event = sd_event_source_unref(manager->inotify_event);
-        manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event);
-
-        manager->event = sd_event_unref(manager->event);
-
-        manager->workers = hashmap_free(manager->workers);
-        event_queue_cleanup(manager, EVENT_UNDEF);
+        manager->inotify_fd = safe_close(manager->inotify_fd);
 
         manager->monitor = sd_device_monitor_unref(manager->monitor);
-        manager->ctrl = udev_ctrl_unref(manager->ctrl);
 
-        manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
+        /* discard queued events and kill workers */
+        event_queue_cleanup(manager, EVENT_QUEUED);
+        manager_kill_workers(manager, true);
 }
 
-static Manager* manager_free(Manager *manager) {
-        if (!manager)
-                return NULL;
+/* reload requested, HUP signal received, rules changed, builtin changed */
+static void manager_reload(Manager *manager) {
 
-        udev_builtin_exit();
+        assert(manager);
 
-        if (manager->pid == getpid_cached())
-                udev_ctrl_cleanup(manager->ctrl);
+        sd_notify(false,
+                  "RELOADING=1\n"
+                  "STATUS=Flushing configuration...");
 
-        manager_clear_for_worker(manager);
+        manager_kill_workers(manager, false);
+        manager->rules = udev_rules_free(manager->rules);
+        udev_builtin_exit();
 
-        sd_netlink_unref(manager->rtnl);
+        sd_notifyf(false,
+                   "READY=1\n"
+                   "STATUS=Processing with %u children at max", arg_children_max);
+}
 
-        hashmap_free_free_free(manager->properties);
-        udev_rules_free(manager->rules);
+static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
+        Manager *manager = userdata;
 
-        safe_close(manager->inotify_fd);
-        safe_close_pair(manager->worker_watch);
+        assert(manager);
 
-        return mfree(manager);
-}
+        log_debug("Cleanup idle workers");
+        manager_kill_workers(manager, false);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+        return 1;
+}
 
 static int worker_send_message(int fd) {
-        struct worker_message message = {};
+        WorkerMessage message = {};
 
         return loop_write(fd, &message, sizeof(message), false);
 }
@@ -591,9 +623,59 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
         return 0;
 }
 
-static int worker_spawn(Manager *manager, struct event *event) {
+static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+        Event *event = userdata;
+
+        assert(event);
+        assert(event->worker);
+
+        kill_and_sigcont(event->worker->pid, arg_timeout_signal);
+        event->worker->state = WORKER_KILLED;
+
+        log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
+
+        return 1;
+}
+
+static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+        Event *event = userdata;
+
+        assert(event);
+        assert(event->worker);
+
+        log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
+
+        return 1;
+}
+
+static void worker_attach_event(Worker *worker, Event *event) {
+        sd_event *e;
+
+        assert(worker);
+        assert(worker->manager);
+        assert(event);
+        assert(!event->worker);
+        assert(!worker->event);
+
+        worker->state = WORKER_RUNNING;
+        worker->event = event;
+        event->state = EVENT_RUNNING;
+        event->worker = worker;
+
+        e = worker->manager->event;
+
+        (void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
+                                          udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC,
+                                          on_event_timeout_warning, event);
+
+        (void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
+                                          arg_event_timeout_usec, USEC_PER_SEC,
+                                          on_event_timeout, event);
+}
+
+static int worker_spawn(Manager *manager, Event *event) {
         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *worker_monitor = NULL;
-        struct worker *worker;
+        Worker *worker;
         pid_t pid;
         int r;
 
@@ -635,16 +717,18 @@ static int worker_spawn(Manager *manager, struct event *event) {
         return 0;
 }
 
-static void event_run(Manager *manager, struct event *event) {
+static int event_run(Event *event) {
         static bool log_children_max_reached = true;
-        struct worker *worker;
+        Manager *manager;
+        Worker *worker;
         int r;
 
-        assert(manager);
         assert(event);
+        assert(event->manager);
 
         log_device_uevent(event->dev, "Device ready for processing");
 
+        manager = event->manager;
         HASHMAP_FOREACH(worker, manager->workers) {
                 if (worker->state != WORKER_IDLE)
                         continue;
@@ -658,109 +742,72 @@ static void event_run(Manager *manager, struct event *event) {
                         continue;
                 }
                 worker_attach_event(worker, event);
-                return;
+                return 1; /* event is now processing. */
         }
 
         if (hashmap_size(manager->workers) >= arg_children_max) {
-
                 /* Avoid spamming the debug logs if the limit is already reached and
                  * many events still need to be processed */
                 if (log_children_max_reached && arg_children_max > 1) {
                         log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
                         log_children_max_reached = false;
                 }
-                return;
+                return 0; /* no free worker */
         }
 
         /* Re-enable the debug message for the next batch of events */
         log_children_max_reached = true;
 
         /* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
-           and, until the next SELinux policy changes, we safe further reloads in future children */
+         * and, until the next SELinux policy changes, we safe further reloads in future children */
         mac_selinux_maybe_reload();
 
         /* start new worker and pass initial device */
-        worker_spawn(manager, event);
-}
-
-static int event_queue_insert(Manager *manager, sd_device *dev) {
-        _cleanup_(sd_device_unrefp) sd_device *clone = NULL;
-        struct event *event;
-        uint64_t seqnum;
-        int r;
-
-        assert(manager);
-        assert(dev);
-
-        /* only one process can add events to the queue */
-        assert(manager->pid == getpid_cached());
-
-        /* We only accepts devices received by device monitor. */
-        r = sd_device_get_seqnum(dev, &seqnum);
+        r = worker_spawn(manager, event);
         if (r < 0)
                 return r;
 
-        /* Save original device to restore the state on failures. */
-        r = device_shallow_clone(dev, &clone);
-        if (r < 0)
-                return r;
-
-        r = device_copy_properties(clone, dev);
-        if (r < 0)
-                return r;
-
-        event = new(struct event, 1);
-        if (!event)
-                return -ENOMEM;
-
-        *event = (struct event) {
-                .manager = manager,
-                .dev = sd_device_ref(dev),
-                .dev_kernel = TAKE_PTR(clone),
-                .seqnum = seqnum,
-                .state = EVENT_QUEUED,
-        };
-
-        if (LIST_IS_EMPTY(manager->events)) {
-                r = touch("/run/udev/queue");
-                if (r < 0)
-                        log_warning_errno(r, "Failed to touch /run/udev/queue: %m");
-        }
-
-        LIST_APPEND(event, manager->events, event);
+        return 1; /* event is now processing. */
+}
 
-        log_device_uevent(dev, "Device is queued");
+static int event_is_blocked(Event *event) {
+        const char *subsystem, *devpath, *devpath_old = NULL;
+        dev_t devnum = makedev(0, 0);
+        Event *loop_event;
+        size_t devpath_len;
+        int r, ifindex = 0;
+        bool is_block;
 
-        return 0;
-}
+        /* lookup event for identical, parent, child device */
 
-static void manager_kill_workers(Manager *manager, bool force) {
-        struct worker *worker;
+        assert(event);
+        assert(event->manager);
+        assert(event->blocker_seqnum <= event->seqnum);
 
-        assert(manager);
+        if (event->blocker_seqnum == event->seqnum)
+                /* we have checked previously and no blocker found */
+                return false;
 
-        HASHMAP_FOREACH(worker, manager->workers) {
-                if (worker->state == WORKER_KILLED)
+        LIST_FOREACH(event, loop_event, event->manager->events) {
+                /* we already found a later event, earlier cannot block us, no need to check again */
+                if (loop_event->seqnum < event->blocker_seqnum)
                         continue;
 
-                if (worker->state == WORKER_RUNNING && !force) {
-                        worker->state = WORKER_KILLING;
-                        continue;
-                }
+                /* event we checked earlier still exists, no need to check again */
+                if (loop_event->seqnum == event->blocker_seqnum)
+                        return true;
 
-                worker->state = WORKER_KILLED;
-                (void) kill(worker->pid, SIGTERM);
+                /* found ourself, no later event can block us */
+                if (loop_event->seqnum >= event->seqnum)
+                        goto no_blocker;
+
+                /* found event we have not checked */
+                break;
         }
-}
 
-/* lookup event for identical, parent, child device */
-static int is_device_busy(Manager *manager, struct event *event) {
-        const char *subsystem, *devpath, *devpath_old = NULL;
-        dev_t devnum = makedev(0, 0);
-        struct event *loop_event;
-        size_t devpath_len;
-        int r, ifindex = 0;
-        bool is_block;
+        assert(loop_event);
+        assert(loop_event->seqnum > event->blocker_seqnum &&
+               loop_event->seqnum < event->seqnum);
 
         r = sd_device_get_subsystem(event->dev, &subsystem);
         if (r < 0)
@@ -787,21 +834,13 @@ static int is_device_busy(Manager *manager, struct event *event) {
                 return r;
 
         /* check if queue contains events we depend on */
-        LIST_FOREACH(event, loop_event, manager->events) {
+        LIST_FOREACH(event, loop_event, loop_event) {
                 size_t loop_devpath_len, common;
                 const char *loop_devpath;
 
-                /* we already found a later event, earlier cannot block us, no need to check again */
-                if (loop_event->seqnum < event->delaying_seqnum)
-                        continue;
-
-                /* event we checked earlier still exists, no need to check again */
-                if (loop_event->seqnum == event->delaying_seqnum)
-                        return true;
-
                 /* found ourself, no later event can block us */
                 if (loop_event->seqnum >= event->seqnum)
-                        break;
+                        goto no_blocker;
 
                 /* check major/minor */
                 if (major(devnum) != 0) {
@@ -813,7 +852,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
 
                         if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
                             devnum == d && is_block == streq(s, "block"))
-                                goto set_delaying_seqnum;
+                                break;
                 }
 
                 /* check network device ifindex */
@@ -822,7 +861,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
 
                         if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
                             ifindex == i)
-                                goto set_delaying_seqnum;
+                                break;
                 }
 
                 if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
@@ -830,7 +869,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
 
                 /* check our old name */
                 if (devpath_old && streq(devpath_old, loop_devpath))
-                        goto set_delaying_seqnum;
+                        break;
 
                 loop_devpath_len = strlen(loop_devpath);
 
@@ -843,80 +882,32 @@ static int is_device_busy(Manager *manager, struct event *event) {
 
                 /* identical device event found */
                 if (devpath_len == loop_devpath_len)
-                        goto set_delaying_seqnum;
+                        break;
 
                 /* parent device event found */
                 if (devpath[common] == '/')
-                        goto set_delaying_seqnum;
+                        break;
 
                 /* child device event found */
                 if (loop_devpath[common] == '/')
-                        goto set_delaying_seqnum;
+                        break;
         }
 
-        return false;
+        assert(loop_event);
 
-set_delaying_seqnum:
         log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
                          event->seqnum, loop_event->seqnum);
 
-        event->delaying_seqnum = loop_event->seqnum;
+        event->blocker_seqnum = loop_event->seqnum;
         return true;
-}
-
-static void manager_exit(Manager *manager) {
-        assert(manager);
-
-        manager->exit = true;
-
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Starting shutdown...");
-
-        /* close sources of new events and discard buffered events */
-        manager->ctrl = udev_ctrl_unref(manager->ctrl);
-
-        manager->inotify_event = sd_event_source_unref(manager->inotify_event);
-        manager->inotify_fd = safe_close(manager->inotify_fd);
-
-        manager->monitor = sd_device_monitor_unref(manager->monitor);
-
-        /* discard queued events and kill workers */
-        event_queue_cleanup(manager, EVENT_QUEUED);
-        manager_kill_workers(manager, true);
-}
-
-/* reload requested, HUP signal received, rules changed, builtin changed */
-static void manager_reload(Manager *manager) {
-
-        assert(manager);
-
-        sd_notify(false,
-                  "RELOADING=1\n"
-                  "STATUS=Flushing configuration...");
-
-        manager_kill_workers(manager, false);
-        manager->rules = udev_rules_free(manager->rules);
-        udev_builtin_exit();
-
-        sd_notifyf(false,
-                   "READY=1\n"
-                   "STATUS=Processing with %u children at max", arg_children_max);
-}
 
-static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
-        Manager *manager = userdata;
-
-        assert(manager);
-
-        log_debug("Cleanup idle workers");
-        manager_kill_workers(manager, false);
-
-        return 1;
+no_blocker:
+        event->blocker_seqnum = event->seqnum;
+        return false;
 }
 
-static void event_queue_start(Manager *manager) {
-        struct event *event;
+static int event_queue_start(Manager *manager) {
+        Event *event, *event_next;
         usec_t usec;
         int r;
 
@@ -924,12 +915,12 @@ static void event_queue_start(Manager *manager) {
 
         if (LIST_IS_EMPTY(manager->events) ||
             manager->exit || manager->stop_exec_queue)
-                return;
+                return 0;
 
         assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0);
         /* check for changed config, every 3 seconds at most */
         if (manager->last_usec == 0 ||
-            usec - manager->last_usec > 3 * USEC_PER_SEC) {
+            usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) {
                 if (udev_rules_check_timestamp(manager->rules) ||
                     udev_builtin_validate())
                         manager_reload(manager);
@@ -945,33 +936,111 @@ static void event_queue_start(Manager *manager) {
 
         if (!manager->rules) {
                 r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
-                if (r < 0) {
-                        log_warning_errno(r, "Failed to read udev rules: %m");
-                        return;
-                }
+                if (r < 0)
+                        return log_warning_errno(r, "Failed to read udev rules: %m");
         }
 
-        LIST_FOREACH(event, event, manager->events) {
+        LIST_FOREACH_SAFE(event, event, event_next, manager->events) {
                 if (event->state != EVENT_QUEUED)
                         continue;
 
-                /* do not start event if parent or child event is still running */
-                if (is_device_busy(manager, event) != 0)
+                /* do not start event if parent or child event is still running or queued */
+                r = event_is_blocked(event);
+                if (r < 0) {
+                        sd_device_action_t a = _SD_DEVICE_ACTION_INVALID;
+
+                        (void) sd_device_get_action(event->dev, &a);
+                        log_device_warning_errno(event->dev, r,
+                                                 "Failed to check event dependency, "
+                                                 "skipping event (SEQNUM=%"PRIu64", ACTION=%s)",
+                                                 event->seqnum,
+                                                 strna(device_action_to_string(a)));
+
+                        event_free(event);
+                        return r;
+                }
+                if (r > 0)
                         continue;
 
-                event_run(manager, event);
+                r = event_run(event);
+                if (r <= 0)
+                        return r;
         }
+
+        return 0;
 }
 
-static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
-        struct event *event, *tmp;
+static int event_queue_insert(Manager *manager, sd_device *dev) {
+        _cleanup_(sd_device_unrefp) sd_device *clone = NULL;
+        Event *event;
+        uint64_t seqnum;
+        int r;
 
-        LIST_FOREACH_SAFE(event, event, tmp, manager->events) {
-                if (match_type != EVENT_UNDEF && match_type != event->state)
-                        continue;
+        assert(manager);
+        assert(dev);
 
-                event_free(event);
+        /* only one process can add events to the queue */
+        assert(manager->pid == getpid_cached());
+
+        /* We only accepts devices received by device monitor. */
+        r = sd_device_get_seqnum(dev, &seqnum);
+        if (r < 0)
+                return r;
+
+        /* Save original device to restore the state on failures. */
+        r = device_shallow_clone(dev, &clone);
+        if (r < 0)
+                return r;
+
+        r = device_copy_properties(clone, dev);
+        if (r < 0)
+                return r;
+
+        event = new(Event, 1);
+        if (!event)
+                return -ENOMEM;
+
+        *event = (Event) {
+                .manager = manager,
+                .dev = sd_device_ref(dev),
+                .dev_kernel = TAKE_PTR(clone),
+                .seqnum = seqnum,
+                .state = EVENT_QUEUED,
+        };
+
+        if (LIST_IS_EMPTY(manager->events)) {
+                r = touch("/run/udev/queue");
+                if (r < 0)
+                        log_warning_errno(r, "Failed to touch /run/udev/queue, ignoring: %m");
+        }
+
+        LIST_APPEND(event, manager->events, event);
+
+        log_device_uevent(dev, "Device is queued");
+
+        return 0;
+}
+
+static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
+        Manager *manager = userdata;
+        int r;
+
+        assert(manager);
+
+        DEVICE_TRACE_POINT(kernel_uevent_received, dev);
+
+        device_ensure_usec_initialized(dev, NULL);
+
+        r = event_queue_insert(manager, dev);
+        if (r < 0) {
+                log_device_error_errno(dev, r, "Failed to insert device into event queue: %m");
+                return 1;
         }
+
+        /* we have fresh events, try to schedule them */
+        event_queue_start(manager);
+
+        return 1;
 }
 
 static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@@ -980,7 +1049,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
         assert(manager);
 
         for (;;) {
-                struct worker_message msg;
+                WorkerMessage msg;
                 struct iovec iovec = {
                         .iov_base = &msg,
                         .iov_len = sizeof(msg),
@@ -994,7 +1063,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
                 };
                 ssize_t size;
                 struct ucred *ucred;
-                struct worker *worker;
+                Worker *worker;
 
                 size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
                 if (size == -EINTR)
@@ -1007,7 +1076,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
 
                 cmsg_close_all(&msghdr);
 
-                if (size != sizeof(struct worker_message)) {
+                if (size != sizeof(WorkerMessage)) {
                         log_warning("Ignoring worker message with invalid size %zi bytes", size);
                         continue;
                 }
@@ -1041,30 +1110,8 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
         return 1;
 }
 
-static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
-        Manager *manager = userdata;
-        int r;
-
-        assert(manager);
-
-        DEVICE_TRACE_POINT(kernel_uevent_received, dev);
-
-        device_ensure_usec_initialized(dev, NULL);
-
-        r = event_queue_insert(manager, dev);
-        if (r < 0) {
-                log_device_error_errno(dev, r, "Failed to insert device into event queue: %m");
-                return 1;
-        }
-
-        /* we have fresh events, try to schedule them */
-        event_queue_start(manager);
-
-        return 1;
-}
-
 /* receive the udevd message from userspace */
-static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) {
+static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
         Manager *manager = userdata;
         int r;
 
@@ -1357,7 +1404,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
         for (;;) {
                 pid_t pid;
                 int status;
-                struct worker *worker;
+                Worker *worker;
 
                 pid = waitpid(-1, &status, WNOHANG);
                 if (pid <= 0)
index 352f00682b66dcfac7f4b6b14f3a7b92c62fd770..8455cc60adf664aa9f99fa2d14a57da4d74a0ae4 100755 (executable)
@@ -11,6 +11,7 @@ TEST_NO_NSPAWN=1
 test_append_files() {
     (
         local workspace="${1:?}"
+        dracut_install busybox
 
         if selinuxenabled >/dev/null; then
             dracut_install selinuxenabled
index 410b1699bf610e830d476e90210362b740890288..abe421c505c0c5f322f92353418fc520949b7885 100644 (file)
@@ -126,7 +126,6 @@ BASICTOOLS=(
     base64
     basename
     bash
-    busybox
     capsh
     cat
     chmod
@@ -229,7 +228,7 @@ is_built_with_asan() {
 
     # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
     local _asan_calls
-    _asan_calls="$(objdump -dC "$SYSTEMD_JOURNALD" | grep -E "(callq?|brasl?)\s+[^ <]+\s+<__asan" -c)"
+    _asan_calls="$(objdump -dC "$SYSTEMD_JOURNALD" | grep -E "(callq?|brasl?|bl)\s.+__asan" -c)"
     if ((_asan_calls < 1000)); then
         return 1
     else
@@ -348,12 +347,14 @@ run_qemu() {
             [ "$ARCH" ] || ARCH=$(uname -m)
             case $ARCH in
                 ppc64*)
-                KERNEL_BIN="/boot/vmlinux-$KERNEL_VER"
-                CONSOLE=hvc0
-                ;;
+                    # Ubuntu ppc64* calls the kernel binary as vmlinux-*, RHEL/CentOS
+                    # uses the "standard" vmlinuz- prefix
+                    [[ -e "/boot/vmlinux-$KERNEL_VER" ]] && KERNEL_BIN="/boot/vmlinux-$KERNEL_VER" || KERNEL_BIN="/boot/vmlinuz-$KERNEL_VER"
+                    CONSOLE=hvc0
+                    ;;
                 *)
-                KERNEL_BIN="/boot/vmlinuz-$KERNEL_VER"
-                ;;
+                    KERNEL_BIN="/boot/vmlinuz-$KERNEL_VER"
+                    ;;
             esac
         fi
     fi
@@ -1681,6 +1682,11 @@ inst_libs() {
 
     while read -r line; do
         [[ "$line" = 'not a dynamic executable' ]] && break
+        # Skip a harmless error when running the tests on a system with a significantly
+        # older systemd version (ldd tries to resolve the unprefixed RPATH for libsystemd.so.0,
+        # which is in this case older than the already installed libsystemd.so.0 in $initdir).
+        # The issue is triggered by installing test dependencies in install_missing_libraries().
+        [[ "$line" =~ libsystemd.so.*:\ version\ .*\ not\ found ]] && continue
 
         if [[ "$line" =~ $so_regex ]]; then
             file="${BASH_REMATCH[1]}"
@@ -2343,7 +2349,7 @@ instmods() {
                 else
                     (
                         [[ "$mpargs" ]] && echo "$mpargs"
-                        find "$mod_dir" -path "*/${mod#=}/*" -type f -printf '%f\n'
+                        find "$mod_dir" -path "*/${mod#=}/*" -name "*.ko*" -type f -printf '%f\n'
                     ) | instmods
                 fi
                 ;;
index df9b6eadad78374854eb4653c34d767f0f3b98fc..d3e3a212e7fe5d5fe755e0829ae85a2f427d4f45 100755 (executable)
@@ -674,9 +674,9 @@ class NetworkctlTests(unittest.TestCase, Utilities):
 
         output = check_output('ip -4 address show dev dummy98')
         print(output)
-        self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
-        self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
-        self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
+        self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
+        self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
+        self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
 
         check_output('ip address del 10.1.2.3/16 dev dummy98')
         check_output('ip address del 10.1.2.4/16 dev dummy98')
@@ -687,9 +687,30 @@ class NetworkctlTests(unittest.TestCase, Utilities):
 
         output = check_output('ip -4 address show dev dummy98')
         print(output)
-        self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
-        self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
-        self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
+        self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
+        self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
+        self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
+
+        remove_unit_from_networkd_path(['25-address-static.network'])
+
+        check_output(*networkctl_cmd, 'reload', env=env)
+        self.wait_operstate('dummy98', 'degraded', setup_state='unmanaged')
+
+        output = check_output('ip -4 address show dev dummy98')
+        print(output)
+        self.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
+        self.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
+        self.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
+
+        copy_unit_to_networkd_unit_path('25-address-static.network')
+        check_output(*networkctl_cmd, 'reload', env=env)
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('ip -4 address show dev dummy98')
+        print(output)
+        self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
+        self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
+        self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
 
     def test_reload(self):
         start_networkd(3)
index 24f0da35abd197430c9c1bf4b7c474eddb1b1486..f81a9e3ace22b942bf66a099ce819cf2443c0586 100644 (file)
@@ -4,4 +4,13 @@ Description=TEST-10-ISSUE-2467
 [Service]
 ExecStartPre=rm -f /failed /testok
 Type=oneshot
-ExecStart=sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test10.socket; printf x >test.file; socat -t20 OPEN:test.file UNIX-CONNECT:/run/test.ctl; >/testok'
+ExecStart=rm -f /tmp/nonexistent
+ExecStart=systemctl start test10.socket
+ExecStart=sh -x -c 'printf x >test.file'
+ExecStart=-socat -T20 OPEN:test.file UNIX-CONNECT:/run/test.ctl
+# TriggerLimitIntervalSec= by default is set to 2s. A "sleep 10" should give
+# systemd enough time even on slower machines, to reach the trigger limit.
+ExecStart=sleep 10
+ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P ActiveState)" = failed'
+ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = trigger-limit-hit'
+ExecStart=sh -x -c 'echo OK >/testok'
diff --git a/units/factory-reset.target b/units/factory-reset.target
new file mode 100644 (file)
index 0000000..99f383d
--- /dev/null
@@ -0,0 +1,12 @@
+#  SPDX-License-Identifier: LGPL-2.1-or-later
+#
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Target that triggers factory reset. Does nothing by default.
+Documentation=man:systemd.special(7)
index 64da9efaafbf1cb8dd906b26392001dd67979186..9398df721ea7aba1eb6980dc7c2493a8a4adfc4a 100644 (file)
@@ -19,6 +19,7 @@ units = [
          'sysinit.target.wants/'],
         ['emergency.target',                    ''],
         ['exit.target',                         ''],
+        ['factory-reset.target',                ''],
         ['final.target',                        ''],
         ['first-boot-complete.target',          ''],
         ['getty.target',                        '',
index e962954f06c0baaa2bc1f47ea51904ceaabb6c47..7aee6463bd54c5cac86379c5640fbf78826a800e 100644 (file)
@@ -11,7 +11,7 @@
 Description=Cleanup of Temporary Directories
 Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
 DefaultDependencies=no
-Conflicts=shutdown.target
+Conflicts=shutdown.target initrd-switch-root.service
 After=local-fs.target time-set.target
 Before=shutdown.target
 
index 3f028d25337770ed6bb25b6e1228106bf80037c5..bc29dbc8c9c1793a514f0d61faa81ddcf51389e8 100644 (file)
@@ -11,7 +11,7 @@
 Description=Create Volatile Files and Directories
 Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
 DefaultDependencies=no
-Conflicts=shutdown.target
+Conflicts=shutdown.target initrd-switch-root.service
 After=local-fs.target systemd-sysusers.service systemd-journald.service
 Before=sysinit.target shutdown.target
 RefuseManualStop=yes