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:
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
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*
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
usb:v1491p0088*
usb:v16D1p1027*
usb:v1C7Ap0300*
-usb:v1C7Ap0570*
usb:v1C7Ap0575*
usb:v27C6p5042*
usb:v27C6p5110*
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
# 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
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
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
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
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
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
<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
<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>
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
<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>
<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>
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>
"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"
"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"
#: 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"
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"
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"
#: 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"
#: 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"
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"
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 "
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
'--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]' \
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;
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)
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;
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;
}
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;
if (k < 0 && r == 0)
r = k;
- k = verify_executables(u);
+ k = verify_executables(u, root);
if (k < 0 && r == 0)
r = k;
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 |
log_debug("Starting manager...");
- r = manager_startup(m, NULL, NULL);
+ r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, root);
if (r < 0)
return r;
}
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;
}
#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);
#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"
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;
}
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) {
ARG_ORDER,
ARG_REQUIRE,
ARG_ROOT,
+ ARG_IMAGE,
ARG_SYSTEM,
ARG_USER,
ARG_GLOBAL,
{ "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 },
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:
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 },
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);
}
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[]) {
#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) \
({ \
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;
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,
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;
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);
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);
#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) \
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)
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;
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)
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. */
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);
#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"
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;
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;
}
__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;
}
#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;
return (ticks_end - ticks_start) * 1000UL;
}
+#endif
UINT64 time_usec(VOID) {
UINT64 ticks;
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);
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;
_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,
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;
}
}
-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);
* 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");
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);
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);
/* 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;
}
}
+ /* 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.");
"\n"
"[Mount]\n");
+ r = write_what(f, what);
+ if (r < 0)
+ return r;
+
if (original_where)
fprintf(f, "# Canonicalized from %s\n", original_where);
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;
#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"
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'))
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)
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;
}
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;
}
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));
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);
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;
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;
[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);
[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;
[HANDLE_HIBERNATE] = "hibernate",
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
[HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
+ [HANDLE_FACTORY_RESET] = "factory-reset",
[HANDLE_LOCK] = "lock",
};
HANDLE_HYBRID_SLEEP,
HANDLE_SUSPEND_THEN_HIBERNATE,
HANDLE_LOCK,
+ HANDLE_FACTORY_RESET,
_HANDLE_ACTION_MAX,
_HANDLE_ACTION_INVALID = -EINVAL,
} HandleAction;
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) {
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,
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;
}
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;
}
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;
}
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)
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);
}
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)
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);
}
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;
}
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;
}
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: {
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: {
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:
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;
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);
}
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;
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) {
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) {
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) {
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);
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);
}
}
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(
#include "conf-parser.h"
typedef struct Link Link;
+typedef struct Network Network;
+typedef struct Request Request;
typedef enum DHCPClientIdentifier {
DHCP_CLIENT_ID_MAC,
} 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);
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.": "");
/* 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);
}
int dhcp6_start(Link *link) {
+ int r;
+
assert(link);
if (!link->dhcp6_client)
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;
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) {
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;
}
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;
}
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;
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);
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) {
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) {
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);
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;
/* 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 {
} 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 */
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);
!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) ||
/* 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),
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) {
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;
}
link_drop_from_master(link);
- link_unref(set_remove(link->manager->links_requesting_uuid, link));
-
(void) unlink(link->state_file);
link_clean(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);
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;
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)
}
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);
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);
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;
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) {
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");
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);
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);
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;
} 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_;
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);
}
}
(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;
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);
DUID duid_product_uuid;
bool has_product_uuid;
bool product_uuid_requested;
- Set *links_requesting_uuid;
char* dynamic_hostname;
char* dynamic_timezone;
#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);
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. */
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;
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);
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;
}
* 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)
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");
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;
}
*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));
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)
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);
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);
#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,
/* 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));
}
#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"
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);
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);
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);
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);
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;
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,
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;
}
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)
k = dns_resource_key_new_consume(key->class, key->type, destination);
if (!k)
- return mfree(destination);
+ return NULL;
+ TAKE_PTR(destination);
return k;
}
}
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);
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);
}
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);
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;
message) < 0)
return -ENOMEM;
- setutxent();
+ utmpx = utxent_start();
r = 0;
#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. */
/* 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);
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);
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);
}
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:
*
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);
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))
}
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)));
}
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)));
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);
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);
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);
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;
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);
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);
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);
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)
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);
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;
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");
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);
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;
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;
+}
#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;
/* last change */
bool jumped;
- bool sync;
int64_t drift_freq;
/* watch for time changes */
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);
int manager_connect(Manager *m);
void manager_disconnect(Manager *m);
+
+int manager_setup_save_time_event(Manager *m);
#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;
"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)
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;
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048
+#SaveIntervalSec=60
/* 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;
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);
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,
return 0;
}
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
+int udev_ctrl_enable_receiving(UdevCtrl *uctrl) {
int r;
assert(uctrl);
return 0;
}
-static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
+static void udev_ctrl_disconnect(UdevCtrl *uctrl) {
if (!uctrl)
return;
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);
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)
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);
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,
}
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;
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);
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,
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;
#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,
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);
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;
}
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;
/* 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);
}
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)
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;
sd_netlink *rtnl;
sd_device_monitor *monitor;
- struct udev_ctrl *ctrl;
+ UdevCtrl *ctrl;
int worker_watch[2];
/* used by udev-watch */
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);
/* 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;
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);
/* 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,
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);
}
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;
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;
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)
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) {
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 */
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)
/* check our old name */
if (devpath_old && streq(devpath_old, loop_devpath))
- goto set_delaying_seqnum;
+ break;
loop_devpath_len = strlen(loop_devpath);
/* 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;
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);
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) {
assert(manager);
for (;;) {
- struct worker_message msg;
+ WorkerMessage msg;
struct iovec iovec = {
.iov_base = &msg,
.iov_len = sizeof(msg),
};
ssize_t size;
struct ucred *ucred;
- struct worker *worker;
+ Worker *worker;
size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
if (size == -EINTR)
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;
}
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;
for (;;) {
pid_t pid;
int status;
- struct worker *worker;
+ Worker *worker;
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
test_append_files() {
(
local workspace="${1:?}"
+ dracut_install busybox
if selinuxenabled >/dev/null; then
dracut_install selinuxenabled
base64
basename
bash
- busybox
capsh
cat
chmod
# 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
[ "$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
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]}"
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
;;
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')
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)
[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'
--- /dev/null
+# 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)
'sysinit.target.wants/'],
['emergency.target', ''],
['exit.target', ''],
+ ['factory-reset.target', ''],
['final.target', ''],
['first-boot-complete.target', ''],
['getty.target', '',
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
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