Compare commits

...

46 Commits

Author SHA1 Message Date
Lennart Poettering 8c5616d7f4
Merge e33d1a2222 into a3c2a9ee5d 2024-09-19 16:39:04 +02:00
Yu Watanabe a3c2a9ee5d
Merge pull request #34486 from DaanDeMeyer/test-process-util
test-process-util: Migrate to new assertion macros
2024-09-19 23:28:15 +09:00
Daan De Meyer 062332f3db
Merge pull request #34481 from yuwata/has-tpm2
tpm2-util: several cleanups for tpm2_support()
2024-09-19 16:22:24 +02:00
Daan De Meyer bc9a9177b2
Merge pull request #34483 from yuwata/network-conf-parser-neighbor-nexthop
network: several cleanups for conf parsers
2024-09-19 13:59:56 +02:00
Daan De Meyer e5c6dcac87 test-process-util: Ignore EINVAL from setresuid() and setresgid()
If we're running in a user namespace with a single user and without
the nobody user, we'll get EINVAL from these system calls so make
sure we handle those gracefully.
2024-09-19 13:42:05 +02:00
Daan De Meyer 34a7ca6db2 test-process-util: Use FORK_REOPEN_LOG everywhere we close all fds
To make sure logging works in the child processes.
2024-09-19 13:42:05 +02:00
Daan De Meyer 397820961d test-process-util: Migrate to new assertion macros 2024-09-19 13:42:03 +02:00
Yu Watanabe 3b16e9f419 man/systemd-analyze: mention required libraries for TPM2 support
Closes #34477.
2024-09-19 19:21:08 +09:00
Yu Watanabe d5a7f3b7d4 tpm2-util: colorize output of 'systemd-analyze has-tpm2' 2024-09-19 19:14:19 +09:00
Yu Watanabe f1c16ca6d6 shell-completion/analyze: add has-tpm2 2024-09-19 19:08:49 +09:00
Yu Watanabe b094398b0f tpm2-util: update comment
has-tpm2 command is moved to systemd-analyze.

Follow-up for 58e359604f.
2024-09-19 19:08:10 +09:00
Yu Watanabe 1ee6570843 tpm2-util: do not load tpm2 libraries when not interested in the existence of the libraries
For example, 'bootctl status' only interested in if the efi has TPM2
support and a TPM2 driver is loaded. Hence, not necessary to load
libtss2.
2024-09-19 19:06:46 +09:00
Yu Watanabe b7f051c91d tpm2-util: introduce tpm2_is_fully_supported() 2024-09-19 19:04:15 +09:00
Yu Watanabe a13ead6814
Merge pull request #34479 from yuwata/sd-json-dispatch-field-table-static
tree-wide: make sd_json_dispatch_field table static
2024-09-19 18:59:17 +09:00
Yu Watanabe f901a7b39f network/nexthop: introduce generic conf parser for [NextHop] section 2024-09-19 18:41:47 +09:00
Yu Watanabe 9b01cf0406 network/nexthop: make conf parsers for Family= and Gateway= independent of each other 2024-09-19 18:41:46 +09:00
Yu Watanabe d5aae0713d network/nexthop: use log_section_warning() and friend 2024-09-19 18:40:38 +09:00
Daan De Meyer 1d8a81eb4e Add ASSERT_OK_ZERO_ERRNO() and ASSERT_OK_EQ_ERRNO() 2024-09-19 11:38:47 +02:00
Daan De Meyer 86c1317270
Merge pull request #34474 from DaanDeMeyer/user-group
Two integration test fixes
2024-09-19 09:20:03 +02:00
Daan De Meyer f4faac2073 test: Run TEST-74-AUX-UTILS in virtual machine
Various tests skip themselves when running in a container so make
sure the test runs in a virtual machine so we get full coverage.
2024-09-19 14:56:34 +09:00
Yu Watanabe 2bcc2a89f3 test: create .netdev file at last
Previously, when the test ran on mkosi, then networkd was not masked, and
might be already started. In that case, the interface test2 would be created
soon after the .netdev file is created, and the .link file would not be
applied to the interface. Hence, the later test case for
'networkctl cat @test2:link' would fail.

This make networkd always started at the beginning of the test, and
.netdev file created after .link file is created. So, .link file is
always applied to the interface created by the .netdev file.
2024-09-19 14:50:10 +09:00
Yu Watanabe 07e6a111c0 man: fix typo
Follow-up for 8aee931e7a.
2024-09-19 09:18:47 +09:00
Yu Watanabe c2648f6e23 efi: fix typo
Follow-up for f4e081051d.
2024-09-19 09:14:25 +09:00
Daan De Meyer 1d5b4317cd ci: Don't add testuser to wheel and systemd-journal groups
This breaks TEST-74-AUX-UTILS when run in a VM as the user gets access
to journal files that the test expects it can't access.
2024-09-19 08:47:53 +09:00
Yu Watanabe 8d6eedd8a3 network/neighbor: use log_section_warning_errno() 2024-09-19 04:03:11 +09:00
Yu Watanabe 91eaa90b81 network/neighbor: introduce generic Neighbor section parser 2024-09-19 03:59:34 +09:00
Yu Watanabe 3b5c5da73a network/neighbor: use struct in_addr_data 2024-09-19 03:58:28 +09:00
Yu Watanabe 1775654e2c conf-parser: drop unnecessary temporary variable 2024-09-19 03:39:15 +09:00
Yu Watanabe 0ea6d55a4b conf-parser: introduce config_parse_in_addr_data() 2024-09-19 03:38:22 +09:00
Yu Watanabe 26d35019de tree-wide: drop unnecessary 'struct' 2024-09-19 01:34:57 +09:00
Yu Watanabe b962338104 nsresource: make sd_json_dispatch_field table static
This also adds missing error check of sd_json_dispatch().

Follow-up for 54452c7b2a.
2024-09-19 01:34:57 +09:00
Yu Watanabe fae0b00434 creds-util: make sd_json_dispatch_field table static 2024-09-19 01:34:57 +09:00
Yu Watanabe f7923ef318 resolve: make sd_json_dispatch_field table static 2024-09-19 01:34:57 +09:00
Yu Watanabe 36df48d863 resolvectl: make sd_json_dispatch_field table static 2024-09-19 01:34:57 +09:00
Yu Watanabe 53c638db16 updatectl: make sd_json_dispatch_field table static
This also fixes memory leak of Version object on failure.

Follow-up for ec15bb71c2.
2024-09-19 01:34:57 +09:00
Yu Watanabe 751a247794 varlinkctl: make sd_json_dispatch_field table static 2024-09-19 01:34:56 +09:00
Yu Watanabe 07dbbda0fc ssh-generator: make sd_json_dispatch_field table static 2024-09-19 01:34:56 +09:00
Yu Watanabe ed4a6c476e machine: make sd_json_dispatch_field table static 2024-09-19 01:34:56 +09:00
Lennart Poettering e33d1a2222 hwbd: use newer KEY_PICKUP_PHONE, KEY_HANGUP_PHONE, KEY_SELECTIVE_SCREENSHOT, KEY_NOTIFICATION_CENTER keycodes where appropriate
According to kernel commit cd80ec795156346236e9b1cd9f5cbff5a9bbd212
these were added expressly for these thinkpads, hence use them now.
2024-09-12 10:04:26 +02:00
Lennart Poettering 57aa23bcc6 hwdb: use KEY_ROTATE_DISPLAY for various cases of display rotation keys
The keycode is reletively new. Let's fix some "FIXMEs" and actually make
use of the keycode wherever it appears appropriate according to
commentary.
2024-09-12 10:04:26 +02:00
Lennart Poettering c1ebb399db hwdb: there's KEY_BRIGHTNESSAUTO these days, hence hook it up where a FIXME suggests that 2024-09-12 10:04:26 +02:00
Lennart Poettering 1ee1997629 hwdb: make key map match comment for one laptop
No idea what the right fix is here, the commnt says "touchpad off" but
uses "f22" which is touchpad "on".

let's trust the comment, because it's more literal, and assume this was
a mistake.
2024-09-12 10:04:26 +02:00
Lennart Poettering a415d73e3c hwdb: f23 → touchpad_off 2024-09-12 10:04:26 +02:00
Lennart Poettering 70eb5b0b7c hwdb: f23 → touchpad_on 2024-09-12 10:04:26 +02:00
Lennart Poettering 380683c22f hwdb: f21 → touchpad_toggle
Similar to the previous commit.
2024-09-12 10:04:25 +02:00
Lennart Poettering 81c8d85744 hwdb: replace f20 hwdb key maps by micmute
See: #34323
2024-09-12 10:03:31 +02:00
39 changed files with 860 additions and 932 deletions

View File

@ -116,8 +116,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:*
KEYBOARD_KEY_d9=brightnessup # Fn+Right
KEYBOARD_KEY_ee=brightnessup # Fn+Right
KEYBOARD_KEY_ef=brightnessdown # Fn+Left
KEYBOARD_KEY_f1=f22 # Fn+F7 Touchpad toggle (off-to-on)
KEYBOARD_KEY_f2=f23 # Fn+F7 Touchpad toggle (on-to-off)
KEYBOARD_KEY_f1=touchpad_on # Fn+F7 Touchpad toggle (off-to-on)
KEYBOARD_KEY_f2=touchpad_off # Fn+F7 Touchpad toggle (on-to-off)
KEYBOARD_KEY_f3=prog2 # "P2" programmable button
KEYBOARD_KEY_f4=prog1 # "P1" programmable button
KEYBOARD_KEY_f5=presentation
@ -127,7 +127,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:*
# Acer kernel driver
evdev:name:Acer WMI hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnAcer*:*
KEYBOARD_KEY_82=f21 # Touchpad toggle
KEYBOARD_KEY_82=touchpad_toggle # Touchpad toggle
# Aspire models
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*:*
@ -186,11 +186,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredator*PH*315-52:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMateB311-31*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMateB311R-31*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMateB311RN-31*:pvr*
KEYBOARD_KEY_8a=f20 # Microphone mute
KEYBOARD_KEY_8a=micmute # Microphone mute
# Travelmate C300
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:*
KEYBOARD_KEY_67=f24 # FIXME: rotate screen
KEYBOARD_KEY_67=rotate_display # rotate screen
KEYBOARD_KEY_68=up
KEYBOARD_KEY_69=down
KEYBOARD_KEY_6b=fn
@ -200,7 +200,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P648-G2-MG*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P648-G3-M*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*P645-S*:*
KEYBOARD_KEY_8a=f20 # Microphone mute button; should be micmute
KEYBOARD_KEY_8a=micmute # Microphone mute button
# on some models this isn't brightnessup
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5210*:*
@ -223,7 +223,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPackard*Bell*:pn*:*
# Swift SF314-511
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnSwiftSF314-511:pvr*
KEYBOARD_KEY_8a=f20 # Fn+F12, microphone mute
KEYBOARD_KEY_8a=micmute # Fn+F12, microphone mute
# Predator PHN16-71
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-71:*
@ -237,7 +237,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredatorPHN16-72:*
# Nitro AN515-58
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnNitro*AN*515-58:pvr*
KEYBOARD_KEY_8a=f20 # Microphone mute button
KEYBOARD_KEY_8a=micmute # Microphone mute button
KEYBOARD_KEY_55=power
###########################################################
@ -246,7 +246,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnNitro*AN*515-58:pvr*
# Alienware/Dell reserves these keys; safe to apply on all their devices
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*:*
KEYBOARD_KEY_81=f21 # Touchpad toggle
KEYBOARD_KEY_81=touchpad_toggle # Touchpad toggle
KEYBOARD_KEY_8a=ejectcd
KEYBOARD_KEY_bf=!prog1 # graphics amplifier, cable plug-in event
KEYBOARD_KEY_c1=!prog2 # graphics amplifier, undock-button event
@ -263,7 +263,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pnM17xR3:*
# Aquarius Cmp NS483
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAquarius*:pnCmp*NS483*:*
KEYBOARD_KEY_56=backslash
KEYBOARD_KEY_76=f21 # Touchpad Toggle
KEYBOARD_KEY_76=touchpad_toggle # Touchpad Toggle
###########################################################
# Asus
@ -277,12 +277,12 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnASUS:pn*:*
evdev:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:*
evdev:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:*
evdev:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:*
KEYBOARD_KEY_6b=f21 # Touchpad Toggle
KEYBOARD_KEY_7c=f20 # Remap micmute to f20
KEYBOARD_KEY_6b=touchpad_toggle # Touchpad Toggle
KEYBOARD_KEY_7c=micmute
# USB keyboard in Asus FX503VD
evdev:input:b0003v0B05p1869*
KEYBOARD_KEY_ff31007c=f20 # Remap micmute to f20
KEYBOARD_KEY_ff31007c=micmute
# Asus TF103C misses the home button in its PNP0C40 GPIO resources
# causing the volume-button mappings to be off by one, correct this
@ -340,15 +340,15 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnNotebook:pnW65_67SZ:*
evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNS50_70MU:*
evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNV4XMB,ME,MZ:*
evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNS5x_NS7xPU:*
KEYBOARD_KEY_f7=f21 # Touchpad Toggle
KEYBOARD_KEY_f8=f21 # Touchpad Toggle
KEYBOARD_KEY_f7=touchpad_toggle # Touchpad Toggle
KEYBOARD_KEY_f8=touchpad_toggle # Touchpad Toggle
evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnV5xTNC_TND_TNE:*
evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnNV4xPZ:*
evdev:atkbd:dmi:bvn*:bvr*:svnNotebook:pnV54x_6x_TU:*
KEYBOARD_KEY_f7=f21 # Touchpad Toggle
KEYBOARD_KEY_f8=f21 # Touchpad Toggle
KEYBOARD_KEY_81=f20 # Fn+4; Mic Mute
KEYBOARD_KEY_f7=touchpad_toggle # Touchpad Toggle
KEYBOARD_KEY_f8=touchpad_toggle # Touchpad Toggle
KEYBOARD_KEY_81=micmute # Fn+4; Mic Mute
###########################################################
# Compal
@ -369,7 +369,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*Evo*N*:*
KEYBOARD_KEY_9f=homepage
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnCompaq:pn*:pvr*:rvn*:rnN14KP6*
KEYBOARD_KEY_76=f21 # Fn+f2 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+f2 toggle touchpad
evdev:input:b0003v049Fp0051*
evdev:input:b0003v049Fp008D*
@ -403,24 +403,24 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*:*
KEYBOARD_KEY_89=ejectclosecd # Fn+F10 Eject CD
KEYBOARD_KEY_8a=suspend # Fn+F1 hibernate
KEYBOARD_KEY_8b=switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle")
KEYBOARD_KEY_8c=unknown # Fn+Right Auto Brightness
KEYBOARD_KEY_8c=brightnessauto # Fn+Right Auto Brightness
KEYBOARD_KEY_8f=switchvideomode # Fn+F7 aspect ratio
KEYBOARD_KEY_90=previoussong # Front panel previous song
KEYBOARD_KEY_91=prog1 # Wi-Fi Catcher (Dell-specific)
KEYBOARD_KEY_92=media # MediaDirect button (house icon)
KEYBOARD_KEY_93=unknown # FIXME Fn+Left Auto Brightness
KEYBOARD_KEY_93=brightnessauto # Fn+Left Auto Brightness
KEYBOARD_KEY_95=camera # Shutter button - Takes a picture if optional camera available
KEYBOARD_KEY_97=email # Tablet email button
KEYBOARD_KEY_98=f21 # FIXME: Tablet screen rotation
KEYBOARD_KEY_98=rotate_display # Tablet screen rotation
KEYBOARD_KEY_99=nextsong # Front panel next song
KEYBOARD_KEY_9a=setup # Tablet tools button
KEYBOARD_KEY_9b=switchvideomode # Display toggle button
KEYBOARD_KEY_9e=f21 # Touchpad toggle
KEYBOARD_KEY_9e=touchpad_toggle # Touchpad toggle
KEYBOARD_KEY_a2=playpause # Front panel play/pause
KEYBOARD_KEY_a4=stopcd # Front panel stop
KEYBOARD_KEY_ed=media # MediaDirect button
KEYBOARD_KEY_d8=screenlock # FIXME: Tablet lock button
KEYBOARD_KEY_d9=f21 # Touchpad toggle
KEYBOARD_KEY_d9=touchpad_toggle # Touchpad toggle
#
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*910:*
@ -462,7 +462,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnStudio*155[78]:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:*
KEYBOARD_KEY_88=! # wireless switch
KEYBOARD_KEY_9e=!f21
KEYBOARD_KEY_9e=!touchpad_toggle
# Dell Latitude E[67]*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*E6*:*
@ -481,7 +481,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDellInc.:pnDellSystemXPSL702X:*
# Dell XPS12 9Q33
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:*
KEYBOARD_KEY_88=wlan
KEYBOARD_KEY_65=direction # Screen Rotate
KEYBOARD_KEY_65=rotate_display # Screen Rotate
# Dell Pro Rugged microphone mute
evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnDellProRugged*:*
@ -493,17 +493,17 @@ evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:*
evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:*
# Dell XPS microphone mute
evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:*
KEYBOARD_KEY_100150=f20 # Mic mute toggle, should be micmute
KEYBOARD_KEY_100150=micmute # Mic mute toggle
# Dell Latitude privacy microphone mute
evdev:name:Dell Privacy Driver:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:*
# Dell Precision privacy microphone mute
evdev:name:Dell Privacy Driver:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:*
KEYBOARD_KEY_120001=f20 # Mic mute toggle, should be micmute
KEYBOARD_KEY_120001=micmute # Mic mute toggle
# Dell Professional Sound Bar AE515
evdev:input:b0003v413CpA506*
KEYBOARD_KEY_b002f=f20 # Mic mute toggle, should be micmute
KEYBOARD_KEY_b002f=micmute # Mic mute toggle
###########################################################
# Everex
@ -511,7 +511,7 @@ evdev:input:b0003v413CpA506*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:*
KEYBOARD_KEY_5c=media
KEYBOARD_KEY_65=f21 # Fn+F5 Touchpad toggle
KEYBOARD_KEY_65=touchpad_toggle # Fn+F5 Touchpad toggle
KEYBOARD_KEY_67=prog3 # Fan speed control button
KEYBOARD_KEY_6f=brightnessup
KEYBOARD_KEY_7f=brightnessdown
@ -550,7 +550,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*Edition*V3505*:*
# Amilo Pro v3205
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*V3205*:*
KEYBOARD_KEY_f4=f21 # FIXME: silent-mode decrease CPU/GPU clock
KEYBOARD_KEY_f4=touchpad_toggle # FIXME: silent-mode decrease CPU/GPU clock
KEYBOARD_KEY_f7=switchvideomode # Fn+F3
# Amilo Si 1520
@ -639,7 +639,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
KEYBOARD_KEY_8c=media # music
KEYBOARD_KEY_8e=dvd
KEYBOARD_KEY_b1=help
KEYBOARD_KEY_b3=unknown # FIXME: Auto brightness
KEYBOARD_KEY_b3=brightnessauto # Auto brightness
KEYBOARD_KEY_d7=wlan
KEYBOARD_KEY_92=brightnessdown # Fn+F7 (Fn+F9 on 6730b)
KEYBOARD_KEY_97=brightnessup # Fn+F8 (Fn+F10 on 6730b)
@ -658,8 +658,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*:*
KEYBOARD_KEY_88=media # FIXME: quick play
KEYBOARD_KEY_b7=print
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
KEYBOARD_KEY_d8=!touchpad_off # touchpad off
KEYBOARD_KEY_d9=!touchpad_on # touchpad on
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:*
KEYBOARD_KEY_b7=print
@ -669,7 +669,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:
# Pavilion 13 x360 (Tablet mode and SYSRQ key)
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:*
KEYBOARD_KEY_d7=!f22 # touchpad off
KEYBOARD_KEY_d7=!touchpad_off # touchpad off
KEYBOARD_KEY_d9=unknown
KEYBOARD_KEY_d2=sysrq # Fn+Print = SYSRQ
@ -687,7 +687,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360Convert
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:*
# ENVY x360 13
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPENVYx360Convertible13*:*
KEYBOARD_KEY_82=f20 # Microphone mute button, should be micmute
KEYBOARD_KEY_82=micmute # Microphone mute button
# Spectre x360 16 2022
evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pn*HP[sS][pP][eE][cC][tT][rR][eE]*x3602-in-1*:*
@ -700,7 +700,7 @@ evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pnHPENVYx3602-in-1*:*
evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:*
KEYBOARD_KEY_f8=unknown # rfkill is also reported by HP Wireless hotkeys
KEYBOARD_KEY_64=calendar
KEYBOARD_KEY_81=f20 # Microphone mute button
KEYBOARD_KEY_81=micmute # Microphone mute button
KEYBOARD_KEY_ee=switchvideomode # Switch display outputs
KEYBOARD_KEY_92=brightnessdown
KEYBOARD_KEY_97=brightnessup
@ -718,15 +718,15 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2230s*:*
# Presario
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Presario*CQ*:*
KEYBOARD_KEY_d8=f21
KEYBOARD_KEY_d9=f21
KEYBOARD_KEY_d8=touchpad_toggle
KEYBOARD_KEY_d9=touchpad_toggle
# 2510p 2530p
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2510p*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2530p*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*G60*Notebook*PC:*
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
KEYBOARD_KEY_d8=!touchpad_off # touchpad off
KEYBOARD_KEY_d9=!touchpad_on # touchpad on
# 2570p
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2570p*:*
@ -740,15 +740,15 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2760p*:*
KEYBOARD_KEY_87=volumedown
KEYBOARD_KEY_92=brightnessdown
KEYBOARD_KEY_97=brightnessup
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
KEYBOARD_KEY_b3=unknown # FIXME: Auto brightness
KEYBOARD_KEY_d8=!touchpad_off # touchpad off
KEYBOARD_KEY_d9=!touchpad_on # touchpad on
KEYBOARD_KEY_b3=brightnessauto # Auto brightness
# TX2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][xX]2*:*
KEYBOARD_KEY_c2=media
KEYBOARD_KEY_d8=!f23 # Toggle touchpad button on tx2 (OFF)
KEYBOARD_KEY_d9=!f22 # Toggle touchpad button on tx2 (ON)
KEYBOARD_KEY_d8=!touchpad_off # Toggle touchpad button on tx2 (OFF)
KEYBOARD_KEY_d9=!touchpad_on # Toggle touchpad button on tx2 (ON)
# Presario 2100
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnPresario*2100*:*
@ -773,8 +773,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8460p:*
# HDX9494nr
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:*
KEYBOARD_KEY_b2=www # Fn+F3
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
KEYBOARD_KEY_d8=!touchpad_off # touchpad off
KEYBOARD_KEY_d9=!touchpad_on # touchpad on
# HP EliteBook 725 G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:*
@ -793,14 +793,14 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHP*ProBook*:*
# HP ZBook
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPZBook*:*
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute
KEYBOARD_KEY_81=micmute # Fn+F8; Microphone mute button
# HP ZBook Studio G5
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPZBookStudioG5*:*
KEYBOARD_KEY_64=calendar # Calendar icon (Fn + F12)
KEYBOARD_KEY_6d=displaytoggle # Display icon
KEYBOARD_KEY_66=connect # Pickup phone button → connect → XF86Go
KEYBOARD_KEY_65=cancel # Hangup phone button → cancel → Cancel
KEYBOARD_KEY_66=pickup_phone # Pickup phone button
KEYBOARD_KEY_65=hangup_phone # Hangup phone button
# HP ZBook 15 G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook15G2:*
@ -808,9 +808,9 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook15G2:*
# HP ProBook 11 G1
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook11G1:*
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute
KEYBOARD_KEY_d8=f21 # touchpad toggle
KEYBOARD_KEY_d9=f21 # touchpad toggle
KEYBOARD_KEY_81=micmute # Fn+F8; Microphone mute button
KEYBOARD_KEY_d8=touchpad_toggle # touchpad toggle
KEYBOARD_KEY_d9=touchpad_toggle # touchpad toggle
# HP ZBook Studio G4
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPZBookStudioG4:*
@ -818,13 +818,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPZBookStudioG4:*
# HP EliteBook Folio 1040 G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBookFolio1040G2:*
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
KEYBOARD_KEY_d8=!touchpad_off # touchpad off
KEYBOARD_KEY_d9=!touchpad_on # touchpad on
# HP EliteBook Folio G1
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPEliteBookFolioG1:*
KEYBOARD_KEY_64=calendar
KEYBOARD_KEY_81=f20
KEYBOARD_KEY_81=micmute
# HP EliteBook 845 G7
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteBook845G7*:pvr*
@ -857,16 +857,16 @@ evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*455*G5*:*
# HP ProBook 11G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPProBook11G2*:pvr*
KEYBOARD_KEY_d8=!f23 # Fn+F2: touchpad off
KEYBOARD_KEY_d9=!f22 # Fn+F2: touchpad on
KEYBOARD_KEY_d8=!touchpad_off # Fn+F2: touchpad off
KEYBOARD_KEY_d9=!touchpad_on # Fn+F2: touchpad on
# HP mt44 Mobile Thin Client
evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*mt44*Mobile*Thin*Client*:*
KEYBOARD_KEY_64=calendar # Calendar icon (Fn + F12)
KEYBOARD_KEY_6d=displaytoggle # Display icon
KEYBOARD_KEY_66=connect # Pickup phone button → connect → XF86Go
KEYBOARD_KEY_65=cancel # Hangup phone button → cancel → Cancel
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute
KEYBOARD_KEY_66=pickup_phone # Pickup phone button
KEYBOARD_KEY_65=hangup_phone # Hangup phone button
KEYBOARD_KEY_81=micmute # Fn+F8; Microphone mute button
KEYBOARD_KEY_85=unknown # lid close; also reported via special evdev
KEYBOARD_KEY_f8=wlan # Wireless HW switch button
@ -884,7 +884,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnOMEN*:pvr*
# HP Dev One
evdev:atkbd:dmi:*:rvnHP:rn8A78:*
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button
KEYBOARD_KEY_81=micmute # Fn+F8; Microphone mute button
KEYBOARD_KEY_f9=prog1 # Fn+F12; Programmable hotkey
# HP Victus
@ -913,7 +913,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPEliteDragonfly13.5inchG3NotebookPC:pvr*
# Huawei WMI hotkeys driver
evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI:*
KEYBOARD_KEY_287=f20 # Microphone mute button, should be micmute
KEYBOARD_KEY_287=micmute # Microphone mute button
# Huawei MACH-WX9 and EUL-WX9
evdev:atkbd:dmi:bvn*:bvr*:svnHUAWEI*:pnMACH-WX9:*
@ -974,7 +974,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:*
# LEAP W502
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnJP-IK:pnLEAPW502:pvr*
KEYBOARD_KEY_76=f21 # touchpad toggle
KEYBOARD_KEY_76=touchpad_toggle # touchpad toggle
###########################################################
# Kvadra
@ -982,7 +982,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnJP-IK:pnLEAPW502:pvr*
# LE14U/LE15U
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnKVADRA*:pn*LE1*U*:*
KEYBOARD_KEY_76=f21 # Fn+F1 Toggle touchpad, sends meta+ctrl+toggle
KEYBOARD_KEY_76=touchpad_toggle # Fn+F1 Toggle touchpad, sends meta+ctrl+toggle
###########################################################
# Lenovo
@ -995,7 +995,7 @@ evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
KEYBOARD_KEY_03=sleep
KEYBOARD_KEY_04=wlan
KEYBOARD_KEY_06=switchvideomode
KEYBOARD_KEY_07=f21
KEYBOARD_KEY_07=touchpad_toggle
KEYBOARD_KEY_08=f24
KEYBOARD_KEY_0b=suspend
KEYBOARD_KEY_0f=brightnessup
@ -1006,13 +1006,13 @@ evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
KEYBOARD_KEY_15=volumedown
KEYBOARD_KEY_16=mute
KEYBOARD_KEY_17=prog1
KEYBOARD_KEY_1a=f20 # Microphone mute button; should be micmute
KEYBOARD_KEY_1a=micmute # Microphone mute button
KEYBOARD_KEY_45=bookmarks
KEYBOARD_KEY_46=prog2 # Fn + PrtSc, on Windows: Snipping tool
KEYBOARD_KEY_46=selective_screenshot # Fn + PrtSc, on Windows: Snipping tool
KEYBOARD_KEY_4a=prog3 # Fn + Right shift, on Windows: No idea
KEYBOARD_KEY_4b=chat # Fn + F9, on Windows: Notifications panel key
KEYBOARD_KEY_4c=connect # Fn + F10, on Windows: Answer (Teams) call
KEYBOARD_KEY_4d=cancel # Fn + F11, on Windows: Hangup/decline (Teams) call
KEYBOARD_KEY_4b=notification_center # Fn + F9, on Windows: Notifications panel key
KEYBOARD_KEY_4c=pickup_phone # Fn + F10, on Windows: Answer (Teams) call
KEYBOARD_KEY_4d=hangup_phone # Fn + F11, on Windows: Hangup/decline (Teams) call
# ThinkPad Keyboard with TrackPoint
evdev:input:b0003v17EFp6009*
@ -1020,14 +1020,14 @@ evdev:input:b0003v17EFp6009*
KEYBOARD_KEY_090013=battery # Fn+F3
KEYBOARD_KEY_090014=wlan # Fn+F5
KEYBOARD_KEY_090016=switchvideomode # Fn+F7
KEYBOARD_KEY_090017=f21 # Fn+F8 touchpad toggle
KEYBOARD_KEY_090017=touchpad_toggle # Fn+F8 touchpad toggle
KEYBOARD_KEY_090019=suspend # Fn+F12
KEYBOARD_KEY_09001a=brightnessup # Fn+Home
KEYBOARD_KEY_09001b=brightnessdown # Fn+End
KEYBOARD_KEY_09001d=zoom # Fn+Space
KEYBOARD_KEY_090011=prog1 # ThinkVantage button
KEYBOARD_KEY_090015=camera # Fn+F6 headset/camera VoIP key ??
KEYBOARD_KEY_090010=f20 # Microphone mute button; should be micmute
KEYBOARD_KEY_090010=micmute # Microphone mute button
# Lenovo 3000
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr*
@ -1049,8 +1049,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:*
KEYBOARD_KEY_b9=brightnessup # does nothing in BIOS
KEYBOARD_KEY_ba=brightnessdown # does nothing in BIOS
KEYBOARD_KEY_f1=camera # BIOS toggles camera power
KEYBOARD_KEY_f2=f21 # touchpad toggle (key alternately emits F2 and F3)
KEYBOARD_KEY_f3=f21
KEYBOARD_KEY_f2=touchpad_toggle # touchpad toggle (key alternately emits F2 and F3)
KEYBOARD_KEY_f3=touchpad_toggle
# Lenovo IdeaPad 5
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrIdeaPad5*:*
@ -1063,11 +1063,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*T*:rvn*
KEYBOARD_KEY_66=screenlock
KEYBOARD_KEY_67=cyclewindows # bezel circular arrow
KEYBOARD_KEY_68=setup # bezel setup / menu
KEYBOARD_KEY_6c=direction # rotate screen
KEYBOARD_KEY_6c=rotate_display # rotate screen
# ThinkPad X6 Tablet
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:rvn*
KEYBOARD_KEY_6c=direction # rotate
KEYBOARD_KEY_6c=rotate_display # rotate
KEYBOARD_KEY_68=leftmeta # toolbox
KEYBOARD_KEY_6b=esc # escape
KEYBOARD_KEY_6d=right # right on d-pad
@ -1078,7 +1078,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:rvn*
# ThinkPad X41 Tablet
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnIBM*:pn18666TU:*
KEYBOARD_KEY_6c=direction # rotate
KEYBOARD_KEY_6c=rotate_display # rotate
KEYBOARD_KEY_68=leftmeta # toolbox
KEYBOARD_KEY_6b=esc # escape
KEYBOARD_KEY_69=enter # enter on d-pad
@ -1086,17 +1086,17 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnIBM*:pn18666TU:*
# IdeaPad
evdev:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
KEYBOARD_KEY_0d=rfkill # airplane mode switch (toggle all wireless devices)
KEYBOARD_KEY_08=f20 # micmute
KEYBOARD_KEY_42=f23
KEYBOARD_KEY_43=f22
KEYBOARD_KEY_08=micmute
KEYBOARD_KEY_42=touchpad_off
KEYBOARD_KEY_43=touchpad_on
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr*
KEYBOARD_KEY_95=media
KEYBOARD_KEY_a3=play
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr*
KEYBOARD_KEY_f1=f21
KEYBOARD_KEY_ce=f20 # micmute
KEYBOARD_KEY_f1=touchpad_toggle
KEYBOARD_KEY_ce=micmute
evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
# Lenovo IdeaPad Flex 5
@ -1117,16 +1117,16 @@ evdev:atkbd:dmi:*:svnLENOVO:*:pvrLenovoYoga300-11IBR:*
evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:pvr*
# Lenovo IdeaPad Z500
evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*5931*:pvr*
KEYBOARD_KEY_f3=f21 # Fn+F6 (toggle touchpad)
KEYBOARD_KEY_f3=touchpad_toggle # Fn+F6 (toggle touchpad)
# V480
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
KEYBOARD_KEY_f1=f21
KEYBOARD_KEY_f1=touchpad_toggle
# Lenovo ThinkCentre M800z/M820z/M920z AIO machines
# key_scancode 00 is KEY_MICMUTE
evdev:name:Microphone Mute Button:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:*
KEYBOARD_KEY_00=f20
KEYBOARD_KEY_00=micmute
# enhanced USB keyboard
evdev:input:b0003v04B3p301B*
@ -1141,7 +1141,7 @@ evdev:input:b0003v04B3p301B*
# Lenovo Ideapad D330-10IGM
evdev:name:SIPODEV Lenovo HID Device:dmi:*:svnLENOVO:*:pvrLenovoideapadD330-10IGM:*
KEYBOARD_KEY_70073=f21 # Fn+Supr (Touchpad toggle)
KEYBOARD_KEY_70073=touchpad_toggle # Fn+Supr (Touchpad toggle)
evdev:name:SIPODEV Lenovo HID Device Consumer Control:dmi:*:svnLENOVO:*:pvrLenovoideapadD330-10IGM:*
KEYBOARD_KEY_c00ff=fn_esc # Fn+Tab (FnLk toggle)
@ -1198,8 +1198,8 @@ evdev:input:b0003v046Dp00*
KEYBOARD_KEY_c102b=cyclewindows # Empty window icon
KEYBOARD_KEY_c102c=fn # Fn key
KEYBOARD_KEY_c102d=www # www text + magnifierglass icon
KEYBOARD_KEY_c1031=connect # Pickup phone button → connect → XF86Go
KEYBOARD_KEY_c1032=cancel # Hangup phone button → cancel → Cancel
KEYBOARD_KEY_c1031=pickup_phone # Pickup phone button
KEYBOARD_KEY_c1032=hangup_phone # Hangup phone button
KEYBOARD_KEY_c1041=help # Help text or icon (Fn + F1)
KEYBOARD_KEY_c1042=wordprocessor # Word icon (Fn + F2)
KEYBOARD_KEY_c1043=spreadsheet # Excel icon (Fn + F3)
@ -1500,7 +1500,7 @@ evdev:input:b0003v1532p0200*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:*
KEYBOARD_KEY_76=f21 # Toggle touchpad, sends meta+ctrl+toggle
KEYBOARD_KEY_76=touchpad_toggle # Toggle touchpad, sends meta+ctrl+toggle
KEYBOARD_KEY_91=config # MSIControl Center
KEYBOARD_KEY_a0=mute # Fn+F9
KEYBOARD_KEY_ae=volumedown # Fn+F7
@ -1509,10 +1509,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:*
KEYBOARD_KEY_c2=ejectcd
KEYBOARD_KEY_df=sleep # Fn+F12
KEYBOARD_KEY_e2=bluetooth # satellite dish2
KEYBOARD_KEY_e4=f21 # Fn+F3 Touchpad disable
KEYBOARD_KEY_e4=touchpad_toggle # Fn+F3 Touchpad disable
KEYBOARD_KEY_ec=email # envelope button
KEYBOARD_KEY_ee=camera # Fn+F6 camera disable
KEYBOARD_KEY_f1=f20 # Microphone mute
KEYBOARD_KEY_f1=micmute # Microphone mute
KEYBOARD_KEY_f2=rotate_display # Rotate screen
KEYBOARD_KEY_f6=wlan # satellite dish1
KEYBOARD_KEY_f7=brightnessdown # Fn+F4
@ -1546,7 +1546,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Prestige*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Modern*:*
KEYBOARD_KEY_91=prog1 # Fn+F7 Creation Center, sometime F7
KEYBOARD_KEY_f2=prog2 # Fn+F12 Screen rotation
KEYBOARD_KEY_f2=rotate_display # Fn+F12 Screen rotation
KEYBOARD_KEY_8d=prog3 # Fn+A Change True Color selections
KEYBOARD_KEY_8c=prog4 # Fn+Z Launch True Color
KEYBOARD_KEY_f5=fn_esc # Fn+esc Toggle the behaviour of Fn keys
@ -1554,8 +1554,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Modern*:*
KEYBOARD_KEY_98=unknown # Lid open
evdev:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][aA][rR]*:*
KEYBOARD_KEY_0213=f22
KEYBOARD_KEY_0214=f23
KEYBOARD_KEY_0213=touchpad_on
KEYBOARD_KEY_0214=touchpad_off
# MSI Claw
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnMicro-StarInternationalCo.,Ltd.:pnClawA1M:*
@ -1568,7 +1568,7 @@ evdev:name:AT Translated Set 2 keyboard:dmi:*:svnMicro-StarInternationalCo.,Ltd.
# VersaPro VG-S
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnNEC:pnPC-VK22TGSGS:pvr*
KEYBOARD_KEY_a8=f21 # Fn+Space touchpad toggle
KEYBOARD_KEY_a8=touchpad_toggle # Fn+Space touchpad toggle
KEYBOARD_KEY_67=brightnessdown # Fn+F7 brightness down
KEYBOARD_KEY_65=brightnessup # Fn+F8 brightness up
KEYBOARD_KEY_71=battery # Fn+F4 ECO
@ -1581,7 +1581,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnNEC:pnPC-VK22TGSGS:pvr*
evdev:input:b0003v15BAp003C*
KEYBOARD_KEY_70066=sleep # Fn+F1
KEYBOARD_KEY_700f6=wlan # Fn+F2
KEYBOARD_KEY_700c7=f21 # Fn+F3 touchpad toggle
KEYBOARD_KEY_700c7=touchpad_toggle # Fn+F3 touchpad toggle
KEYBOARD_KEY_7006f=brightnessdown # Fn+F7
KEYBOARD_KEY_70070=brightnessup # Fn+F8
KEYBOARD_KEY_7006e=switchvideomode # Fn+F9
@ -1622,8 +1622,8 @@ evdev:name:AT Translated Set 2 keyboard:phys:sp/serio*/input*:ev:120013:*
KEYBOARD_KEY_f3=f17
KEYBOARD_KEY_f2=f18
KEYBOARD_KEY_f1=f19
KEYBOARD_KEY_f0=f20 # micmute
KEYBOARD_KEY_ef=f21
KEYBOARD_KEY_f0=micmute
KEYBOARD_KEY_ef=touchpad_toggle
KEYBOARD_KEY_ee=chat
KEYBOARD_KEY_e4=chat
KEYBOARD_KEY_dd=menu # Frame
@ -1665,7 +1665,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnONKYO*CORPORATION:pnONKYOPC:*
KEYBOARD_KEY_f0=media # Fn+R
KEYBOARD_KEY_f5=switchvideomode # Fn+E
KEYBOARD_KEY_f6=camera # Fn+T
KEYBOARD_KEY_f7=f21 # Fn+Y (touchpad toggle)
KEYBOARD_KEY_f7=touchpad_toggle # Fn+Y (touchpad toggle)
KEYBOARD_KEY_f8=brightnessup # Fn+S
KEYBOARD_KEY_f9=brightnessdown # Fn+A
KEYBOARD_KEY_fb=wlan # Fn+J
@ -1741,7 +1741,7 @@ evdev:input:b0003v258Ap001E*
# Plantronics .Audio 626 DSP
evdev:input:b0003v047FpC006*
KEYBOARD_KEY_b002f=f20 # Microphone mute button; should be micmute
KEYBOARD_KEY_b002f=micmute # Microphone mute button
###########################################################
# Purism
@ -1806,8 +1806,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*:*
KEYBOARD_KEY_b4=!wlan # Fn+F9 (X60P)
KEYBOARD_KEY_c5=!prog3 # Fn+F8 switch power mode (battery/dynamic/performance)
KEYBOARD_KEY_d5=!wlan # Fn+F12 wlan/airplane switch
KEYBOARD_KEY_f7=!f22 # Fn+F10 Touchpad on
KEYBOARD_KEY_f9=!f23 # Fn+F10 Touchpad off
KEYBOARD_KEY_f7=!touchpad_on # Fn+F10 Touchpad on
KEYBOARD_KEY_f9=!touchpad_off # Fn+F10 Touchpad off
# Series 3
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:*
@ -1820,8 +1820,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*355V[45]*:pvr*
KEYBOARD_KEY_89=!brightnessdown # Fn+F2 brightness down
KEYBOARD_KEY_88=!brightnessup # Fn+F3 brightness up
KEYBOARD_KEY_82=!switchvideomode # Fn+F4 display toggle
KEYBOARD_KEY_f7=!f22 # Fn+F5 touchpad on
KEYBOARD_KEY_f9=!f23 # Fn+F5 touchpad off
KEYBOARD_KEY_f7=!touchpad_on # Fn+F5 touchpad on
KEYBOARD_KEY_f9=!touchpad_off # Fn+F5 touchpad off
KEYBOARD_KEY_a0=!mute # Fn+F6 mute
KEYBOARD_KEY_ae=!volumedown # Fn+F7 volume down
KEYBOARD_KEY_b0=!volumeup # Fn+F8 volume up
@ -1901,8 +1901,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*SX20S*:*
KEYBOARD_KEY_74=mute
KEYBOARD_KEY_75=mute
KEYBOARD_KEY_77=f22 # Touchpad on
KEYBOARD_KEY_79=f23 # Touchpad off
KEYBOARD_KEY_77=touchpad_on # Touchpad on
KEYBOARD_KEY_79=touchpad_off # Touchpad off
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:*
KEYBOARD_KEY_ad=leftmeta
@ -1959,7 +1959,7 @@ evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW250*:*
KEYBOARD_KEY_10=suspend # Fn+F12
evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:*
KEYBOARD_KEY_05=f21 # Fn+F1 -> KEY_F21 (The actual touchpad toggle)
KEYBOARD_KEY_05=touchpad_toggle # Fn+F1
KEYBOARD_KEY_0d=down # Fn+F9 zoomout
KEYBOARD_KEY_0e=up # Fn+F10 zoomin
@ -1968,19 +1968,19 @@ evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:*
###########################################################
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnSystem76*:pn*:*
KEYBOARD_KEY_f7=f21 # Touchpad toggle
KEYBOARD_KEY_f8=f21 # Touchpad toggle
KEYBOARD_KEY_f7=touchpad_toggle # Touchpad toggle
KEYBOARD_KEY_f8=touchpad_toggle # Touchpad toggle
# Pangolin 12
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnSystem76*:pnPangolin*:pvrpang12*
KEYBOARD_KEY_76=f21 # Touchpad toggle
KEYBOARD_KEY_76=touchpad_toggle # Touchpad toggle
###########################################################
# T-bao
###########################################################
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnT-bao:pnTbookair:*
KEYBOARD_KEY_76=f21 # Touchpad toggle
KEYBOARD_KEY_76=touchpad_toggle # Touchpad toggle
###########################################################
# Toshiba
@ -1996,8 +1996,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:*
KEYBOARD_KEY_92=stop
KEYBOARD_KEY_93=www
KEYBOARD_KEY_94=media
KEYBOARD_KEY_9e=f22 # Touchpad on
KEYBOARD_KEY_9f=f23 # Touchpad off
KEYBOARD_KEY_9e=touchpad_on # Touchpad on
KEYBOARD_KEY_9f=touchpad_off # Touchpad off
KEYBOARD_KEY_b9=nextsong
KEYBOARD_KEY_d9=brightnessup
KEYBOARD_KEY_ee=screenlock
@ -2010,8 +2010,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:*
KEYBOARD_KEY_d9=brightnessup
KEYBOARD_KEY_ee=screenlock
KEYBOARD_KEY_93=media
KEYBOARD_KEY_9e=f22 # touchpad enable
KEYBOARD_KEY_9f=f23 # touchpad disable
KEYBOARD_KEY_9e=touchpad_on # touchpad enable
KEYBOARD_KEY_9f=touchpad_off # touchpad disable
# Satellite P75-A
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:*
@ -2025,14 +2025,14 @@ evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITEU940:*
KEYBOARD_KEY_13c=brightnessdown
KEYBOARD_KEY_13d=brightnessup
KEYBOARD_KEY_13e=switchvideomode
KEYBOARD_KEY_13f=f21 # Touchpad toggle
KEYBOARD_KEY_13f=touchpad_toggle # Touchpad toggle
# Satellite P75-A7200
evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:*
KEYBOARD_KEY_13c=brightnessdown
KEYBOARD_KEY_13d=brightnessup
KEYBOARD_KEY_13e=switchvideomode
KEYBOARD_KEY_13f=f21 # Touchpad toggle
KEYBOARD_KEY_13f=touchpad_toggle # Touchpad toggle
KEYBOARD_KEY_9e=wlan
# Portege Z830 ACPI quickstart buttons
@ -2043,7 +2043,7 @@ evdev:name:Quickstart Button 2:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
KEYBOARD_KEY_1=prog2 # TOSHIBA Presentation button
evdev:name:Quickstart Button 3:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
KEYBOARD_KEY_1=f21 # Touchpad toggle
KEYBOARD_KEY_1=touchpad_toggle # Touchpad toggle
###########################################################
# VIA
@ -2057,7 +2057,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:*
###########################################################
evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:bd*:svnVIOS:pnLTH17:*
KEYBOARD_KEY_70073=f21 # Touchpad toggle
KEYBOARD_KEY_70073=touchpad_toggle # Touchpad toggle
###########################################################
# WeiHeng
@ -2065,7 +2065,7 @@ evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:bd*:svnVIOS:pnLTH17:*
# P325J
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINET:pnP325J:*
KEYBOARD_KEY_76=f21 # Touchpad toggle
KEYBOARD_KEY_76=touchpad_toggle # Touchpad toggle
###########################################################
# Xiaomi
@ -2091,8 +2091,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote:*
KEYBOARD_KEY_93=switchvideomode # Fn+F3 Toggle Video Output
KEYBOARD_KEY_95=brightnessdown # Fn+F4 Brightness Down
KEYBOARD_KEY_91=brightnessup # Fn+F5 Brightness Up
KEYBOARD_KEY_a5=f23 # Fn+F6 Disable Touchpad
KEYBOARD_KEY_a6=f22 # Fn+F6 Enable Touchpad
KEYBOARD_KEY_a5=touchpad_off # Fn+F6 Disable Touchpad
KEYBOARD_KEY_a6=touchpad_on # Fn+F6 Enable Touchpad
KEYBOARD_KEY_a7=bluetooth # Fn+F10 Enable Bluetooth
KEYBOARD_KEY_a9=bluetooth # Fn+F10 Disable Bluetooth
KEYBOARD_KEY_f1=wlan # RF Switch Off
@ -2192,7 +2192,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnViewSonic:pnVPAD10:*
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO:pnVJPW1[12]F11X*:pvr*:*
# Vaio FE14 (VJFE41F11X, VJE42F11X, VJFE44F11X, VJFE54F11X)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO:pnVJFE*:pvr*:*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+F1 toggle touchpad
###########################################################
# Positivo
@ -2203,23 +2203,23 @@ evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnCF40CM-V2*
# Positivo DUO (k116)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnK116*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+F1 toggle touchpad
# Positivo (N14NPE-N, N15NPE-N)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivo*:pn*:pvr*:rvnPositivo*:rnN1[45]NPE-N*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+F1 toggle touchpad
KEYBOARD_KEY_dd=search
# Positivo (N15EPE, N14EPE)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivo*:pn*:pvr*:rvnPositivo*:rnN1[45]EPE*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+F1 toggle touchpad
KEYBOARD_KEY_6e=search
# Positivo (CG15D)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnCG15D*
# Positivo Motion (N14AP7, N14DP6, N14DP7, N14DP7-V2, N14DP9, N14JP6, N14KP6)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnN14[ADJK]P*
KEYBOARD_KEY_76=f21 # Fn+f2 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+f2 toggle touchpad
KEYBOARD_KEY_67=prog1 # Programmable button
KEYBOARD_KEY_68=prog2 # Programmable button
KEYBOARD_KEY_69=prog3 # Programmable button
@ -2233,7 +2233,7 @@ evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn
evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:br*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnN14EP6*
# Positivo Motion (CW14Q01P) (CW14Q01P-V2)
evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnCW14Q01P*
KEYBOARD_KEY_70073=f21 # Fn+f2 toggle touchpad
KEYBOARD_KEY_70073=touchpad_toggle # Fn+f2 toggle touchpad
KEYBOARD_KEY_7006b=prog1 # Programmable button
KEYBOARD_KEY_7006c=prog2 # Programmable button
KEYBOARD_KEY_7006d=prog3 # Programmable button
@ -2244,7 +2244,7 @@ evdev:name:SIPODEV USB Composite Device:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn
###########################################################
# Multilaser Ultra (UL154)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*bvr*:svnMultilaserIndustrial:pn*:pvr*:rvn*:rnUL154*
KEYBOARD_KEY_76=f21 # Fn+f2 toggle touchpad
KEYBOARD_KEY_76=touchpad_toggle # Fn+f2 toggle touchpad
###########################################################
# Other

View File

@ -962,7 +962,9 @@ default ignore - -</programlisting>
discovered/supported/used, prints <literal>no</literal>. Otherwise prints
<literal>partial</literal>. In either of these two cases exits with non-zero exit status. It also shows
five lines indicating separately whether firmware, drivers, the system, the kernel and libraries
discovered/support/use TPM2.</para>
discovered/support/use TPM2. Currently, required libraries are <filename>libtss2-esys.so.0</filename>,
<filename>libtss2-rc.so.0</filename>, and <filename>libtss2-mu.so.0</filename>. The requirement may be
changed in the future release.</para>
<para>Note, this checks for TPM 2.0 devices only, and does not consider TPM 1.2 at all.</para>

View File

@ -29,7 +29,7 @@
<refsect1>
<title>Description</title>
<para><command>systemd-nsresourced</command> is a system service that permits transient delegation of a a
<para><command>systemd-nsresourced</command> is a system service that permits transient delegation of a
UID/GID range to a user namespace (see <citerefentry
project='man-pages'><refentrytitle>user_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>)
allocated by a client, via a Varlink IPC API.</para>

View File

@ -3,18 +3,11 @@
set -e
set -o nounset
if [[ "$DISTRIBUTION" =~ ubuntu|debian ]]; then
SUDO_GROUP=sudo
else
SUDO_GROUP=wheel
fi
useradd \
--uid 4711 \
--user-group \
--create-home \
--password "$(openssl passwd -1 testuser)" \
--groups "$SUDO_GROUP",systemd-journal \
--shell /bin/bash \
testuser

View File

@ -67,7 +67,7 @@ _systemd_analyze() {
)
local -A VERBS=(
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk'
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2'
[CRITICAL_CHAIN]='critical-chain'
[DOT]='dot'
[DUMP]='dump'

View File

@ -73,6 +73,7 @@ JSON or table format'
'timespan:Parse a systemd syntax timespan'
'security:Analyze security settings of a service'
'inspect-elf:Parse and print ELF package metadata'
'has-tpm2:Report whether TPM2 support is available'
# log-level, log-target, service-watchdogs have been deprecated
)

View File

@ -96,7 +96,7 @@ int verb_pcrs(int argc, char *argv[], void *userdata) {
const char *alg = NULL;
int r;
if (tpm2_support() != TPM2_SUPPORT_FULL)
if (!tpm2_is_fully_supported())
log_notice("System lacks full TPM2 support, not showing PCR state.");
else {
r = get_pcr_alg(&alg);

View File

@ -411,7 +411,6 @@ int verb_status(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
uint64_t loader_features = 0, stub_features = 0;
Tpm2Support s;
int have;
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
@ -440,7 +439,7 @@ int verb_status(int argc, char *argv[], void *userdata) {
else
printf("\n");
s = tpm2_support();
Tpm2Support s = tpm2_support_full(TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER);
printf(" TPM2 Support: %s%s%s\n",
FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() :
(s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),

View File

@ -450,7 +450,7 @@ static size_t pe_section_table_find_profile_length(
assert(start >= section_table);
assert(start < section_table + n_section_table);
/* Look for the next .profile (or the end of the table), this is where the the sections for this
/* Look for the next .profile (or the end of the table), this is where the sections for this
* profile end. The base profile does not start with a .profile, the others do, hence conditionally
* skip over the first entry. */
const PeSectionHeader *e;
@ -485,7 +485,7 @@ EFI_STATUS pe_locate_profile_sections(
if (!p)
return EFI_NOT_FOUND;
/* Look for the next .profile (or the end of the table), this is where the the sections for this
/* Look for the next .profile (or the end of the table), this is where the sections for this
* profile end. */
size_t n = pe_section_table_find_profile_length(section_table, n_section_table, p, profile);

View File

@ -1005,7 +1005,7 @@ static int validate_stub(void) {
bool found = false;
int r;
if (tpm2_support() != TPM2_SUPPORT_FULL)
if (!tpm2_is_fully_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Sorry, system lacks full TPM2 support.");
r = efi_stub_get_features(&features);

View File

@ -1229,7 +1229,7 @@ static int generic_method_get_interface_description(
sd_varlink_method_flags_t flags,
void *userdata) {
static const struct sd_json_dispatch_field dispatch_table[] = {
static const sd_json_dispatch_field dispatch_table[] = {
{ "interface", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
{}
};

View File

@ -416,19 +416,18 @@ static int list_machine_one(sd_varlink *link, Machine *m, bool more) {
}
static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
const char *mn = NULL;
const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&mn), 0 },
static const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 },
{}
};
Manager *m = ASSERT_PTR(userdata);
const char *mn = NULL;
int r;
assert(parameters);
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
r = sd_varlink_dispatch(link, parameters, dispatch_table, &mn);
if (r != 0)
return r;

View File

@ -97,8 +97,8 @@ static int neighbor_append_json(Neighbor *n, sd_json_variant **array) {
return sd_json_variant_append_arraybo(
array,
SD_JSON_BUILD_PAIR_INTEGER("Family", n->family),
JSON_BUILD_PAIR_IN_ADDR("Destination", &n->in_addr, n->family),
SD_JSON_BUILD_PAIR_INTEGER("Family", n->dst_addr.family),
JSON_BUILD_PAIR_IN_ADDR("Destination", &n->dst_addr.address, n->dst_addr.family),
JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n->ll_addr),
SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
SD_JSON_BUILD_PAIR_STRING("ConfigState", state));
@ -168,7 +168,7 @@ static int nexthop_append_json(NextHop *n, sd_json_variant **array) {
return sd_json_variant_append_arraybo(
array,
SD_JSON_BUILD_PAIR_UNSIGNED("ID", n->id),
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw, n->family),
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw.address, n->family),
SD_JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags),
SD_JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
SD_JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol),

View File

@ -147,29 +147,29 @@ static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
assert(neighbor);
siphash24_compress_typesafe(neighbor->family, state);
siphash24_compress_typesafe(neighbor->dst_addr.family, state);
if (!IN_SET(neighbor->family, AF_INET, AF_INET6))
if (!IN_SET(neighbor->dst_addr.family, AF_INET, AF_INET6))
/* treat any other address family as AF_UNSPEC */
return;
/* Equality of neighbors are given by the destination address.
* See neigh_lookup() in the kernel. */
in_addr_hash_func(&neighbor->in_addr, neighbor->family, state);
in_addr_hash_func(&neighbor->dst_addr.address, neighbor->dst_addr.family, state);
}
static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
int r;
r = CMP(a->family, b->family);
r = CMP(a->dst_addr.family, b->dst_addr.family);
if (r != 0)
return r;
if (!IN_SET(a->family, AF_INET, AF_INET6))
if (!IN_SET(a->dst_addr.family, AF_INET, AF_INET6))
/* treat any other address family as AF_UNSPEC */
return 0;
return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
return memcmp(&a->dst_addr.address, &b->dst_addr.address, FAMILY_ADDRESS_SIZE(a->dst_addr.family));
}
static int neighbor_get_request(Link *link, const Neighbor *neighbor, Request **ret) {
@ -244,7 +244,7 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
"%s %s neighbor (%s): lladdr: %s, dst: %s",
str, strna(network_config_source_to_string(neighbor->source)), strna(state),
HW_ADDR_TO_STR(&neighbor->ll_addr),
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr));
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address));
}
static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
@ -261,7 +261,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
log_neighbor_debug(neighbor, "Configuring", link);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH,
link->ifindex, neighbor->family);
link->ifindex, neighbor->dst_addr.family);
if (r < 0)
return r;
@ -273,7 +273,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
if (r < 0)
return r;
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->dst_addr.family, &neighbor->dst_addr.address);
if (r < 0)
return r;
@ -338,7 +338,7 @@ static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
"The link layer address length (%zu) for neighbor %s does not match with "
"the hardware address length (%zu), ignoring the setting.",
neighbor->ll_addr.length,
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address),
link->hw_addr.length);
return 0;
}
@ -451,11 +451,11 @@ int neighbor_remove(Neighbor *neighbor, Link *link) {
log_neighbor_debug(neighbor, "Removing", link);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_DELNEIGH,
link->ifindex, neighbor->family);
link->ifindex, neighbor->dst_addr.family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->dst_addr.family, &neighbor->dst_addr.address);
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
@ -593,19 +593,19 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return log_oom();
/* First, retrieve the fundamental information about the neighbor. */
r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
r = sd_rtnl_message_neigh_get_family(message, &tmp->dst_addr.family);
if (r < 0) {
log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
return 0;
}
if (tmp->family == AF_BRIDGE) /* Currently, we do not support it. */
if (tmp->dst_addr.family == AF_BRIDGE) /* Currently, we do not support it. */
return 0;
if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
if (!IN_SET(tmp->dst_addr.family, AF_INET, AF_INET6)) {
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->dst_addr.family);
return 0;
}
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->family, &tmp->in_addr);
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->dst_addr.family, &tmp->dst_addr.address);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
return 0;
@ -660,28 +660,28 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return 1;
}
#define log_neighbor_section(neighbor, fmt, ...) \
({ \
const Neighbor *_neighbor = (neighbor); \
log_section_warning_errno( \
_neighbor ? _neighbor->section : NULL, \
SYNTHETIC_ERRNO(EINVAL), \
fmt " Ignoring [Neighbor] section.", \
##__VA_ARGS__); \
})
static int neighbor_section_verify(Neighbor *neighbor) {
if (section_is_invalid(neighbor->section))
return -EINVAL;
if (neighbor->family == AF_UNSPEC)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Neighbor section without Address= configured. "
"Ignoring [Neighbor] section from line %u.",
neighbor->section->filename, neighbor->section->line);
if (neighbor->dst_addr.family == AF_UNSPEC)
return log_neighbor_section(neighbor, "Neighbor section without Address= configured.");
if (neighbor->family == AF_INET6 && !socket_ipv6_is_supported())
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Neighbor section with an IPv6 destination address configured, "
"but the kernel does not support IPv6. "
"Ignoring [Neighbor] section from line %u.",
neighbor->section->filename, neighbor->section->line);
if (neighbor->dst_addr.family == AF_INET6 && !socket_ipv6_is_supported())
return log_neighbor_section(neighbor, "Neighbor section with an IPv6 destination address configured, but the kernel does not support IPv6.");
if (neighbor->ll_addr.length == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Neighbor section without LinkLayerAddress= configured. "
"Ignoring [Neighbor] section from line %u.",
neighbor->section->filename, neighbor->section->line);
return log_neighbor_section(neighbor, "Neighbor section without LinkLayerAddress= configured.");
return 0;
}
@ -709,7 +709,7 @@ int network_drop_invalid_neighbors(Network *network) {
log_warning("%s: Duplicated neighbor settings for %s is specified at line %u and %u, "
"dropping the neighbor setting specified at line %u.",
dup->section->filename,
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address),
neighbor->section->line,
dup->section->line, dup->section->line);
/* neighbor_detach() will drop the neighbor from neighbors_by_section. */
@ -728,7 +728,7 @@ int network_drop_invalid_neighbors(Network *network) {
}
int config_parse_neighbor_address(
int config_parse_neighbor_section(
const char *unit,
const char *filename,
unsigned line,
@ -740,76 +740,26 @@ int config_parse_neighbor_address(
void *data,
void *userdata) {
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
static const ConfigSectionParser table[_NEIGHBOR_CONF_PARSER_MAX] = {
[NEIGHBOR_DESTINATION_ADDRESS] = { .parser = config_parse_in_addr_data, .ltype = 0, .offset = offsetof(Neighbor, dst_addr), },
[NEIGHBOR_LINK_LAYER_ADDRESS] = { .parser = config_parse_hw_addr, .ltype = 0, .offset = offsetof(Neighbor, ll_addr), },
};
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *neighbor = NULL;
Network *network = ASSERT_PTR(userdata);
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
r = neighbor_new_static(network, filename, section_line, &n);
r = neighbor_new_static(network, filename, section_line, &neighbor);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->family = AF_UNSPEC;
n->in_addr = IN_ADDR_NULL;
TAKE_PTR(n);
return 0;
}
r = config_section_parse(table, ELEMENTSOF(table),
unit, filename, line, section, section_line, lvalue, ltype, rvalue, neighbor);
if (r <= 0) /* 0 means non-critical error, but the section will be ignored. */
return r;
r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Neighbor Address is invalid, ignoring assignment: %s", rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
int config_parse_neighbor_lladdr(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
Network *network = ASSERT_PTR(userdata);
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
r = neighbor_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->ll_addr = HW_ADDR_NULL;
TAKE_PTR(n);
return 0;
}
r = parse_hw_addr(rvalue, &n->ll_addr);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Neighbor %s= is invalid, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
TAKE_PTR(neighbor);
return 0;
}

View File

@ -23,8 +23,7 @@ typedef struct Neighbor {
unsigned n_ref;
int family;
union in_addr_union in_addr;
struct in_addr_data dst_addr;
struct hw_addr_data ll_addr;
} Neighbor;
@ -46,5 +45,11 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Neighbor, neighbor);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_lladdr);
typedef enum NeighborConfParserType {
NEIGHBOR_DESTINATION_ADDRESS,
NEIGHBOR_LINK_LAYER_ADDRESS,
_NEIGHBOR_CONF_PARSER_MAX,
_NEIGHBOR_CONF_PARSER_INVALID = -EINVAL,
} NeighborConfParserType;
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_section);

View File

@ -173,9 +173,9 @@ Address.NetLabel, config_parse_address_section,
Address.NFTSet, config_parse_address_section, ADDRESS_NFT_SET, 0
IPv6AddressLabel.Prefix, config_parse_ipv6_address_label_section, IPV6_ADDRESS_LABEL_PREFIX, 0
IPv6AddressLabel.Label, config_parse_ipv6_address_label_section, IPV6_ADDRESS_LABEL, 0
Neighbor.Address, config_parse_neighbor_address, 0, 0
Neighbor.LinkLayerAddress, config_parse_neighbor_lladdr, 0, 0
Neighbor.MACAddress, config_parse_neighbor_lladdr, 0, 0 /* deprecated */
Neighbor.Address, config_parse_neighbor_section, NEIGHBOR_DESTINATION_ADDRESS, 0
Neighbor.LinkLayerAddress, config_parse_neighbor_section, NEIGHBOR_LINK_LAYER_ADDRESS, 0
Neighbor.MACAddress, config_parse_neighbor_section, NEIGHBOR_LINK_LAYER_ADDRESS, 0 /* deprecated */
RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_TOS, 0
RoutingPolicyRule.Priority, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_PRIORITY, 0
RoutingPolicyRule.GoTo, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_GOTO, 0
@ -219,12 +219,12 @@ Route.QuickAck, config_parse_route_metric_boolean,
Route.TCPCongestionControlAlgorithm, config_parse_route_metric_tcp_congestion, RTAX_CC_ALGO, 0
Route.FastOpenNoCookie, config_parse_route_metric_boolean, RTAX_FASTOPEN_NO_COOKIE, 0
Route.TTLPropagate, config_parse_warn_compat, DISABLED_LEGACY, 0
NextHop.Id, config_parse_nexthop_id, 0, 0
NextHop.Gateway, config_parse_nexthop_gateway, 0, 0
NextHop.Family, config_parse_nexthop_family, 0, 0
NextHop.OnLink, config_parse_nexthop_onlink, 0, 0
NextHop.Blackhole, config_parse_nexthop_blackhole, 0, 0
NextHop.Group, config_parse_nexthop_group, 0, 0
NextHop.Id, config_parse_nexthop_section, NEXTHOP_ID, 0
NextHop.Gateway, config_parse_nexthop_section, NEXTHOP_GATEWAY, 0
NextHop.Family, config_parse_nexthop_section, NEXTHOP_FAMILY, 0
NextHop.OnLink, config_parse_nexthop_section, NEXTHOP_ONLINK, 0
NextHop.Blackhole, config_parse_nexthop_section, NEXTHOP_BLACKHOLE, 0
NextHop.Group, config_parse_nexthop_section, NEXTHOP_GROUP, 0
DHCPv4.RequestAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_request_address)
DHCPv4.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCPv4.UseDNS, config_parse_tristate, 0, offsetof(Network, dhcp_use_dns)

View File

@ -854,7 +854,7 @@ bool network_has_static_ipv6_configurations(Network *network) {
return true;
ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
if (neighbor->family == AF_INET6)
if (neighbor->dst_addr.family == AF_INET6)
return true;
if (!hashmap_isempty(network->address_labels_by_section))

View File

@ -236,7 +236,7 @@ static int nexthop_compare_full(const NextHop *a, const NextHop *b) {
return r;
if (IN_SET(a->family, AF_INET, AF_INET6)) {
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
r = memcmp(&a->gw.address, &b->gw.address, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
}
@ -481,7 +481,7 @@ static void log_nexthop_debug(const NextHop *nexthop, const char *str, Manager *
log_link_debug(link, "%s %s nexthop (%s): id: %"PRIu32", gw: %s, blackhole: %s, group: %s, flags: %s",
str, strna(network_config_source_to_string(nexthop->source)), strna(state),
nexthop->id,
IN_ADDR_TO_STRING(nexthop->family, &nexthop->gw),
IN_ADDR_TO_STRING(nexthop->family, &nexthop->gw.address),
yes_no(nexthop->blackhole), strna(group), strna(flags));
}
@ -627,8 +627,8 @@ static int nexthop_configure(NextHop *nexthop, Link *link, Request *req) {
if (r < 0)
return r;
if (in_addr_is_set(nexthop->family, &nexthop->gw)) {
r = netlink_message_append_in_addr_union(m, NHA_GATEWAY, nexthop->family, &nexthop->gw);
if (in_addr_is_set(nexthop->family, &nexthop->gw.address)) {
r = netlink_message_append_in_addr_union(m, NHA_GATEWAY, nexthop->family, &nexthop->gw.address);
if (r < 0)
return r;
@ -722,7 +722,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
return r;
}
return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw);
return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw.address);
}
static int nexthop_process_request(Request *req, Link *link, NextHop *nexthop) {
@ -1093,9 +1093,9 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
(void) nexthop_update_group(nexthop, message);
if (nexthop->family != AF_UNSPEC) {
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, nexthop->family, &nexthop->gw);
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, nexthop->family, &nexthop->gw.address);
if (r == -ENODATA)
nexthop->gw = IN_ADDR_NULL;
nexthop->gw.address = IN_ADDR_NULL;
else if (r < 0)
log_debug_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
}
@ -1129,66 +1129,60 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
return 1;
}
#define log_nexthop_section(nexthop, fmt, ...) \
({ \
const NextHop *_nexthop = (nexthop); \
log_section_warning_errno( \
_nexthop ? _nexthop->section : NULL, \
SYNTHETIC_ERRNO(EINVAL), \
fmt " Ignoring [NextHop] section.", \
##__VA_ARGS__); \
})
static int nexthop_section_verify(NextHop *nh) {
if (section_is_invalid(nh->section))
return -EINVAL;
if (!nh->network->manager->manage_foreign_nexthops && nh->id == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: [NextHop] section without specifying Id= is not supported "
"if ManageForeignNextHops=no is set in networkd.conf. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop without specifying Id= is not supported if ManageForeignNextHops=no is set in networkd.conf.");
if (nh->family == AF_UNSPEC)
nh->family = nh->gw.family;
else if (nh->gw.family != AF_UNSPEC && nh->gw.family != nh->family)
return log_nexthop_section(nh, "Family= and Gateway= settings for nexthop contradict each other.");
assert(nh->gw.family == nh->family || nh->gw.family == AF_UNSPEC);
if (!hashmap_isempty(nh->group)) {
if (in_addr_is_set(nh->family, &nh->gw))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot have gateway address. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
if (in_addr_is_set(nh->family, &nh->gw.address))
return log_nexthop_section(nh, "Nexthop group cannot have gateway address.");
if (nh->family != AF_UNSPEC)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot have Family= setting. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop group cannot have Family= setting.");
if (nh->blackhole)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot be a blackhole. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop group cannot be a blackhole.");
if (nh->onlink > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot have on-link flag. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop group cannot have on-link flag.");
} else if (nh->family == AF_UNSPEC)
/* When neither Family=, Gateway=, nor Group= is specified, assume IPv4. */
nh->family = AF_INET;
if (nh->blackhole) {
if (in_addr_is_set(nh->family, &nh->gw))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: blackhole nexthop cannot have gateway address. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
if (in_addr_is_set(nh->family, &nh->gw.address))
return log_nexthop_section(nh, "Blackhole nexthop cannot have gateway address.");
if (nh->onlink > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: blackhole nexthop cannot have on-link flag. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Blackhole nexthop cannot have on-link flag.");
}
if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw) &&
if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw.address) &&
ordered_hashmap_isempty(nh->network->addresses_by_section)) {
/* If no address is configured, in most cases the gateway cannot be reachable.
* TODO: we may need to improve the condition above. */
log_warning("%s: Gateway= without static address configured. "
"Enabling OnLink= option.",
nh->section->filename);
log_section_warning(nh->section, "Nexthop with Gateway= specified, but no static address configured. Enabling OnLink= option.");
nh->onlink = true;
}
@ -1262,7 +1256,7 @@ int manager_build_nexthop_ids(Manager *manager) {
return 0;
}
int config_parse_nexthop_id(
static int config_parse_nexthop_family(
const char *unit,
const char *filename,
unsigned line,
@ -1274,261 +1268,38 @@ int config_parse_nexthop_id(
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
uint32_t id;
int *family = ASSERT_PTR(data);
if (isempty(rvalue))
*family = AF_UNSPEC;
else if (streq(rvalue, "ipv4"))
*family = AF_INET;
else if (streq(rvalue, "ipv6"))
*family = AF_INET6;
else
return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
return 1;
}
static int config_parse_nexthop_group(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Hashmap **group = ASSERT_PTR(data);
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->id = 0;
TAKE_PTR(n);
return 0;
}
r = safe_atou32(rvalue, &id);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Could not parse nexthop id \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
if (id == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid nexthop id \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
n->id = id;
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_gateway(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->family = AF_UNSPEC;
n->gw = IN_ADDR_NULL;
TAKE_PTR(n);
return 0;
}
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_family(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
AddressFamily a;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue) &&
!in_addr_is_set(n->family, &n->gw)) {
/* Accept an empty string only when Gateway= is null or not specified. */
n->family = AF_UNSPEC;
TAKE_PTR(n);
return 0;
}
a = nexthop_address_family_from_string(rvalue);
if (a < 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
if (in_addr_is_set(n->family, &n->gw) &&
((a == ADDRESS_FAMILY_IPV4 && n->family == AF_INET6) ||
(a == ADDRESS_FAMILY_IPV6 && n->family == AF_INET))) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Specified family '%s' conflicts with the family of the previously specified Gateway=, "
"ignoring assignment.", rvalue);
return 0;
}
switch (a) {
case ADDRESS_FAMILY_IPV4:
n->family = AF_INET;
break;
case ADDRESS_FAMILY_IPV6:
n->family = AF_INET6;
break;
default:
assert_not_reached();
}
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_onlink(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
r = parse_tristate(rvalue, &n->onlink);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_blackhole(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
n->blackhole = r;
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_group(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->group = hashmap_free_free(n->group);
TAKE_PTR(n);
return 0;
*group = hashmap_free_free(*group);
return 1;
}
for (const char *p = rvalue;;) {
@ -1538,15 +1309,10 @@ int config_parse_nexthop_group(
char *sep;
r = extract_first_word(&p, &word, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (r == 0)
break;
return 1;
nhg = new0(struct nexthop_grp, 1);
if (!nhg)
@ -1586,7 +1352,7 @@ int config_parse_nexthop_group(
continue;
}
r = hashmap_ensure_put(&n->group, NULL, UINT32_TO_PTR(nhg->id), nhg);
r = hashmap_ensure_put(group, NULL, UINT32_TO_PTR(nhg->id), nhg);
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST) {
@ -1598,7 +1364,44 @@ int config_parse_nexthop_group(
assert(r > 0);
TAKE_PTR(nhg);
}
}
TAKE_PTR(n);
int config_parse_nexthop_section(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
static const ConfigSectionParser table[_NEXTHOP_CONF_PARSER_MAX] = {
[NEXTHOP_ID] = { .parser = config_parse_uint32, .ltype = 0, .offset = offsetof(NextHop, id), },
[NEXTHOP_GATEWAY] = { .parser = config_parse_in_addr_data, .ltype = 0, .offset = offsetof(NextHop, gw), },
[NEXTHOP_FAMILY] = { .parser = config_parse_nexthop_family, .ltype = 0, .offset = offsetof(NextHop, family), },
[NEXTHOP_ONLINK] = { .parser = config_parse_tristate, .ltype = 0, .offset = offsetof(NextHop, onlink), },
[NEXTHOP_BLACKHOLE] = { .parser = config_parse_bool, .ltype = 0, .offset = offsetof(NextHop, blackhole), },
[NEXTHOP_GROUP] = { .parser = config_parse_nexthop_group, .ltype = 0, .offset = offsetof(NextHop, group), },
};
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *nexthop = NULL;
Network *network = ASSERT_PTR(userdata);
int r;
assert(filename);
r = nexthop_new_static(network, filename, section_line, &nexthop);
if (r < 0)
return log_oom();
r = config_section_parse(table, ELEMENTSOF(table),
unit, filename, line, section, section_line, lvalue, ltype, rvalue, nexthop);
if (r <= 0) /* 0 means non-critical error, but the section will be ignored. */
return r;
TAKE_PTR(nexthop);
return 0;
}

View File

@ -36,7 +36,7 @@ typedef struct NextHop {
Hashmap *group; /* NHA_GROUP */
bool blackhole; /* NHA_BLACKHOLE */
int ifindex; /* NHA_OIF */
union in_addr_union gw; /* NHA_GATEWAY */
struct in_addr_data gw; /* NHA_GATEWAY, gw.family is only used by conf parser. */
/* Only used in conf parser and nexthop_section_verify(). */
int onlink;
@ -71,9 +71,15 @@ int manager_build_nexthop_ids(Manager *manager);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(NextHop, nexthop);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_family);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_onlink);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_blackhole);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_group);
typedef enum NextHopConfParserType {
NEXTHOP_ID,
NEXTHOP_GATEWAY,
NEXTHOP_FAMILY,
NEXTHOP_ONLINK,
NEXTHOP_BLACKHOLE,
NEXTHOP_GROUP,
_NEXTHOP_CONF_PARSER_MAX,
_NEXTHOP_CONF_PARSER_INVALID = -EINVAL,
} NextHopConfParserType;
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_section);

View File

@ -1742,7 +1742,7 @@ static int oci_seccomp_args(const char *name, sd_json_variant *v, sd_json_dispat
int r;
JSON_VARIANT_ARRAY_FOREACH(e, v) {
static const struct sd_json_dispatch_field table[] = {
static const sd_json_dispatch_field table[] = {
{ "index", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, offsetof(struct scmp_arg_cmp, arg), SD_JSON_MANDATORY },
{ "value", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_a), SD_JSON_MANDATORY },
{ "valueTwo", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_b), 0 },

View File

@ -369,7 +369,7 @@ static int run(int argc, char *argv[]) {
event = TPM2_EVENT_PHASE;
}
if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
if (arg_graceful && !tpm2_is_fully_supported()) {
log_notice("No complete TPM2 support detected, exiting gracefully.");
return EXIT_SUCCESS;
}

View File

@ -2876,55 +2876,76 @@ static int print_answer(sd_json_variant *answer) {
return 0;
}
typedef struct MonitorQueryParams {
sd_json_variant *question;
sd_json_variant *answer;
sd_json_variant *collected_questions;
int rcode;
int error;
int ede_code;
const char *state;
const char *result;
const char *ede_msg;
} MonitorQueryParams;
static void monitor_query_params_done(MonitorQueryParams *p) {
assert(p);
sd_json_variant_unref(p->question);
sd_json_variant_unref(p->answer);
sd_json_variant_unref(p->collected_questions);
}
static void monitor_query_dump(sd_json_variant *v) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *question = NULL, *answer = NULL, *collected_questions = NULL;
int rcode = -1, error = 0, ede_code = -1;
const char *state = NULL, *result = NULL, *ede_msg = NULL;
assert(v);
sd_json_dispatch_field dispatch_table[] = {
{ "question", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&question), SD_JSON_MANDATORY },
{ "answer", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&answer), 0 },
{ "collectedQuestions", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&collected_questions), 0 },
{ "state", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&state), SD_JSON_MANDATORY },
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&result), 0 },
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&rcode), 0 },
{ "errno", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&error), 0 },
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&ede_code), 0 },
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&ede_msg), 0 },
static const sd_json_dispatch_field dispatch_table[] = {
{ "question", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, question), SD_JSON_MANDATORY },
{ "answer", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, answer), 0 },
{ "collectedQuestions", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, collected_questions), 0 },
{ "state", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, state), SD_JSON_MANDATORY },
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, result), 0 },
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, rcode), 0 },
{ "errno", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, error), 0 },
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, ede_code), 0 },
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, ede_msg), 0 },
{}
};
if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, NULL) < 0)
_cleanup_(monitor_query_params_done) MonitorQueryParams p = {
.rcode = -1,
.ede_code = -1,
};
assert(v);
if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &p) < 0)
return;
/* First show the current question */
print_question('Q', ansi_highlight_cyan(), question);
print_question('Q', ansi_highlight_cyan(), p.question);
/* And then show the questions that led to this one in case this was a CNAME chain */
print_question('C', ansi_highlight_grey(), collected_questions);
print_question('C', ansi_highlight_grey(), p.collected_questions);
printf("%s%s S%s: %s",
streq_ptr(state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
streq_ptr(p.state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
special_glyph(SPECIAL_GLYPH_ARROW_LEFT),
ansi_normal(),
strna(streq_ptr(state, "errno") ? errno_to_name(error) :
streq_ptr(state, "rcode-failure") ? dns_rcode_to_string(rcode) :
state));
strna(streq_ptr(p.state, "errno") ? errno_to_name(p.error) :
streq_ptr(p.state, "rcode-failure") ? dns_rcode_to_string(p.rcode) :
p.state));
if (!isempty(result))
printf(": %s", result);
if (!isempty(p.result))
printf(": %s", p.result);
if (ede_code >= 0)
if (p.ede_code >= 0)
printf(" (%s%s%s)",
FORMAT_DNS_EDE_RCODE(ede_code),
!isempty(ede_msg) ? ": " : "",
strempty(ede_msg));
FORMAT_DNS_EDE_RCODE(p.ede_code),
!isempty(p.ede_msg) ? ": " : "",
strempty(p.ede_msg));
puts("");
print_answer(answer);
print_answer(p.answer);
}
static int monitor_reply(

View File

@ -2145,26 +2145,31 @@ int dns_resource_key_to_json(DnsResourceKey *key, sd_json_variant **ret) {
}
int dns_resource_key_from_json(sd_json_variant *v, DnsResourceKey **ret) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
uint16_t type = 0, class = 0;
const char *name = NULL;
int r;
struct params {
uint16_t type;
uint16_t class;
const char *name;
};
sd_json_dispatch_field dispatch_table[] = {
{ "class", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, PTR_TO_SIZE(&class), SD_JSON_MANDATORY },
{ "type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, PTR_TO_SIZE(&type), SD_JSON_MANDATORY },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&name), SD_JSON_MANDATORY },
static const sd_json_dispatch_field dispatch_table[] = {
{ "class", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct params, class), SD_JSON_MANDATORY },
{ "type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct params, type), SD_JSON_MANDATORY },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct params, name), SD_JSON_MANDATORY },
{}
};
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
struct params p;
int r;
assert(v);
assert(ret);
r = sd_json_dispatch(v, dispatch_table, 0, NULL);
r = sd_json_dispatch(v, dispatch_table, 0, &p);
if (r < 0)
return r;
key = dns_resource_key_new(class, type, name);
key = dns_resource_key_new(p.class, p.type, p.name);
if (!key)
return -ENOMEM;

View File

@ -667,7 +667,7 @@ static int has_tpm2(void) {
*
* Note that we don't check if we ourselves are built with TPM2 support here! */
return FLAGS_SET(tpm2_support(), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE);
return FLAGS_SET(tpm2_support_full(TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE);
}
static int condition_test_security(Condition *c, char **env) {

View File

@ -1764,7 +1764,7 @@ int config_parse_hw_addr(
void *data,
void *userdata) {
struct hw_addr_data a, *hwaddr = ASSERT_PTR(data);
struct hw_addr_data *hwaddr = ASSERT_PTR(data);
int r;
assert(filename);
@ -1776,11 +1776,10 @@ int config_parse_hw_addr(
return 1;
}
r = parse_hw_addr_full(rvalue, ltype, &a);
r = parse_hw_addr_full(rvalue, ltype, hwaddr);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
*hwaddr = a;
return 1;
}
@ -1973,6 +1972,36 @@ int config_parse_in_addr_non_null(
return 1;
}
int config_parse_in_addr_data(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
struct in_addr_data *p = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
if (isempty(rvalue)) {
*p = (struct in_addr_data) {};
return 1;
}
r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
return 1;
}
int config_parse_unsigned_bounded(
const char *unit,
const char *filename,

View File

@ -304,6 +304,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_hw_addrs);
CONFIG_PARSER_PROTOTYPE(config_parse_ether_addr);
CONFIG_PARSER_PROTOTYPE(config_parse_ether_addrs);
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_non_null);
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_data);
CONFIG_PARSER_PROTOTYPE(config_parse_percent);
CONFIG_PARSER_PROTOTYPE(config_parse_permyriad);
CONFIG_PARSER_PROTOTYPE(config_parse_pid);

View File

@ -886,7 +886,7 @@ int encrypt_credential_and_warn(
* container tpm2_support will detect this, and will return a different flag combination of
* TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */
try_tpm2 = tpm2_support() == TPM2_SUPPORT_FULL;
try_tpm2 = tpm2_is_fully_supported();
if (!try_tpm2)
log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2.");
} else
@ -1582,14 +1582,12 @@ int ipc_encrypt_credential(const char *name, usec_t timestamp, usec_t not_after,
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to encrypt: %s", error_id);
}
r = sd_json_dispatch(
reply,
(const sd_json_dispatch_field[]) {
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), SD_JSON_MANDATORY },
{},
},
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, 0, SD_JSON_MANDATORY },
{},
};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
if (r < 0)
return r;
@ -1649,14 +1647,12 @@ int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp,
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to decrypt: %s", error_id);
}
r = sd_json_dispatch(
reply,
(const sd_json_dispatch_field[]) {
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), SD_JSON_MANDATORY },
{},
},
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, 0, SD_JSON_MANDATORY },
{},
};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
if (r < 0)
return r;

View File

@ -250,6 +250,18 @@ int nsresource_add_cgroup(int userns_fd, int cgroup_fd) {
return 1;
}
typedef struct InterfaceParams {
char *host_interface_name;
char *namespace_interface_name;
} InterfaceParams;
static void interface_params_done(InterfaceParams *p) {
assert(p);
free(p->host_interface_name);
free(p->namespace_interface_name);
}
int nsresource_add_netif(
int userns_fd,
int netns_fd,
@ -313,20 +325,20 @@ int nsresource_add_netif(
if (error_id)
return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id);
_cleanup_free_ char *host_interface_name = NULL, *namespace_interface_name = NULL;
r = sd_json_dispatch(
reply,
(const sd_json_dispatch_field[]) {
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&host_interface_name) },
{ "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&namespace_interface_name) },
},
SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), 0 },
{ "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, namespace_interface_name), 0 },
};
_cleanup_(interface_params_done) InterfaceParams p = {};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
if (r < 0)
return r;
if (ret_host_ifname)
*ret_host_ifname = TAKE_PTR(host_interface_name);
*ret_host_ifname = TAKE_PTR(p.host_interface_name);
if (ret_namespace_ifname)
*ret_namespace_ifname = TAKE_PTR(namespace_interface_name);
*ret_namespace_ifname = TAKE_PTR(p.namespace_interface_name);
return 1;
}

View File

@ -281,6 +281,44 @@ static inline int run_test_table(void) {
} \
})
#define ASSERT_OK_ZERO_ERRNO(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) { \
log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
PROJECT_FILE, __LINE__, #expr); \
abort(); \
} \
if (_result != 0) { \
char _sexpr[DECIMAL_STR_MAX(typeof(expr))]; \
xsprintf(_sexpr, DECIMAL_STR_FMT(_result), _result); \
log_error("%s:%i: Assertion failed: expected \"%s\" to be zero, but it is %s.", \
PROJECT_FILE, __LINE__, #expr, _sexpr); \
abort(); \
} \
})
#define ASSERT_OK_EQ_ERRNO(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (_expr1 < 0) { \
log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
PROJECT_FILE, __LINE__, #expr1); \
abort(); \
} \
if (_expr1 != _expr2) { \
char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
log_error("%s:%i: Assertion failed: expected \"%s == %s\", but %s != %s", \
PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
abort(); \
} \
})
#define ASSERT_FAIL(expr) \
({ \
typeof(expr) _result = (expr); \

View File

@ -3,6 +3,7 @@
#include <sys/file.h>
#include "alloc-util.h"
#include "ansi-color.h"
#include "constants.h"
#include "creds-util.h"
#include "cryptsetup-util.h"
@ -7872,11 +7873,11 @@ int tpm2_sym_mode_from_string(const char *mode) {
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown symmetric mode name '%s'", mode);
}
Tpm2Support tpm2_support(void) {
Tpm2Support tpm2_support_full(Tpm2Support mask) {
Tpm2Support support = TPM2_SUPPORT_NONE;
int r;
if (detect_container() <= 0) {
if (((mask & (TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_DRIVER)) != 0) && detect_container() <= 0) {
/* Check if there's a /dev/tpmrm* device via sysfs. If we run in a container we likely just
* got the host sysfs mounted. Since devices are generally not virtualized for containers,
* let's assume containers never have a TPM, at least for now. */
@ -7893,18 +7894,24 @@ Tpm2Support tpm2_support(void) {
support |= TPM2_SUPPORT_SUBSYSTEM;
}
if (efi_has_tpm2())
if (FLAGS_SET(mask, TPM2_SUPPORT_FIRMWARE) && efi_has_tpm2())
support |= TPM2_SUPPORT_FIRMWARE;
#if HAVE_TPM2
support |= TPM2_SUPPORT_SYSTEM;
r = dlopen_tpm2();
if (r >= 0)
support |= TPM2_SUPPORT_LIBRARIES;
if (FLAGS_SET(mask, TPM2_SUPPORT_LIBRARIES)) {
r = dlopen_tpm2();
if (r >= 0)
support |= TPM2_SUPPORT_LIBRARIES;
}
#endif
return support;
return support & mask;
}
static void print_field(const char *s, bool supported) {
printf("%s%s%s%s\n", supported ? ansi_green() : ansi_red(), plus_minus(supported), s, ansi_normal());
}
int verb_has_tpm2_generic(bool quiet) {
@ -7914,22 +7921,17 @@ int verb_has_tpm2_generic(bool quiet) {
if (!quiet) {
if (s == TPM2_SUPPORT_FULL)
puts("yes");
printf("%syes%s\n", ansi_green(), ansi_normal());
else if (s == TPM2_SUPPORT_NONE)
puts("no");
printf("%sno%s\n", ansi_red(), ansi_normal());
else
puts("partial");
printf("%spartial%s\n", ansi_yellow(), ansi_normal());
printf("%sfirmware\n"
"%sdriver\n"
"%ssystem\n"
"%ssubsystem\n"
"%slibraries\n",
plus_minus(s & TPM2_SUPPORT_FIRMWARE),
plus_minus(s & TPM2_SUPPORT_DRIVER),
plus_minus(s & TPM2_SUPPORT_SYSTEM),
plus_minus(s & TPM2_SUPPORT_SUBSYSTEM),
plus_minus(s & TPM2_SUPPORT_LIBRARIES));
print_field("firmware", FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE));
print_field("driver", FLAGS_SET(s, TPM2_SUPPORT_DRIVER));
print_field("system", FLAGS_SET(s, TPM2_SUPPORT_SYSTEM));
print_field("subsystem", FLAGS_SET(s, TPM2_SUPPORT_SUBSYSTEM));
print_field("libraries", FLAGS_SET(s, TPM2_SUPPORT_LIBRARIES));
}
/* Return inverted bit flags. So that TPM2_SUPPORT_FULL becomes EXIT_SUCCESS and the other values

View File

@ -450,8 +450,8 @@ typedef struct {
} systemd_tpm2_plugin_params;
typedef enum Tpm2Support {
/* NOTE! The systemd-creds tool returns these flags 1:1 as exit status. Hence these flags are pretty
* much ABI! Hence, be extra careful when changing/extending these definitions. */
/* NOTE! The systemd-analyze has-tpm2 command returns these flags 1:1 as exit status. Hence these
* flags are pretty much ABI! Hence, be extra careful when changing/extending these definitions. */
TPM2_SUPPORT_NONE = 0, /* no support */
TPM2_SUPPORT_FIRMWARE = 1 << 0, /* firmware reports TPM2 was used */
TPM2_SUPPORT_DRIVER = 1 << 1, /* the kernel has a driver loaded for it */
@ -461,7 +461,13 @@ typedef enum Tpm2Support {
TPM2_SUPPORT_FULL = TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER|TPM2_SUPPORT_SYSTEM|TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_LIBRARIES,
} Tpm2Support;
Tpm2Support tpm2_support(void);
Tpm2Support tpm2_support_full(Tpm2Support mask);
static inline Tpm2Support tpm2_support(void) {
return tpm2_support_full(TPM2_SUPPORT_FULL);
}
static inline bool tpm2_is_fully_supported(void) {
return tpm2_support() == TPM2_SUPPORT_FULL;
}
int verb_has_tpm2_generic(bool quiet);

View File

@ -161,12 +161,12 @@ static int process_machine(const char *machine, const char *port) {
uint32_t cid = VMADDR_CID_ANY;
const sd_json_dispatch_field dispatch_table[] = {
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, PTR_TO_SIZE(&cid), 0 },
static const sd_json_dispatch_field dispatch_table[] = {
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, 0, 0 },
{}
};
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, NULL);
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &cid);
if (r < 0)
return log_error_errno(r, "Failed to parse Varlink reply: %m");

View File

@ -321,12 +321,27 @@ static int list_targets(sd_bus *bus) {
return table_print_with_pager(table, SD_JSON_FORMAT_OFF, arg_pager_flags, arg_legend);
}
typedef struct DescribeParams {
Version v;
sd_json_variant *contents_json;
bool newest;
bool available;
bool installed;
bool obsolete;
bool protected;
bool incomplete;
} DescribeParams;
static void describe_params_done(DescribeParams *p) {
assert(p);
version_done(&p->v);
sd_json_variant_unref(p->contents_json);
}
static int parse_describe(sd_bus_message *reply, Version *ret) {
Version v = {};
char *version_json = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL, *contents_json = NULL;
bool newest = false, available = false, installed = false, obsolete = false, protected = false,
incomplete = false;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL;
int r;
assert(reply);
@ -342,36 +357,37 @@ static int parse_describe(sd_bus_message *reply, Version *ret) {
assert(sd_json_variant_is_object(json));
r = sd_json_dispatch(json,
(const sd_json_dispatch_field[]) {
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&v.version), 0 },
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&newest), 0 },
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&available), 0 },
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&installed), 0 },
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&obsolete), 0 },
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&protected), 0 },
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&incomplete), 0 },
{ "changelog_urls", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, PTR_TO_SIZE(&v.changelog), 0 },
{ "contents", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&contents_json), 0 },
{},
},
SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DescribeParams, v.version), 0 },
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, newest), 0 },
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, available), 0 },
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, installed), 0 },
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, obsolete), 0 },
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, protected), 0 },
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, incomplete), 0 },
{ "changelog_urls", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(DescribeParams, v.changelog), 0 },
{ "contents", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(DescribeParams, contents_json), 0 },
{},
};
_cleanup_(describe_params_done) DescribeParams p = {};
r = sd_json_dispatch(json, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
if (r < 0)
return log_error_errno(r, "Failed to parse JSON: %m");
SET_FLAG(v.flags, UPDATE_NEWEST, newest);
SET_FLAG(v.flags, UPDATE_AVAILABLE, available);
SET_FLAG(v.flags, UPDATE_INSTALLED, installed);
SET_FLAG(v.flags, UPDATE_OBSOLETE, obsolete);
SET_FLAG(v.flags, UPDATE_PROTECTED, protected);
SET_FLAG(v.flags, UPDATE_INCOMPLETE, incomplete);
SET_FLAG(p.v.flags, UPDATE_NEWEST, p.newest);
SET_FLAG(p.v.flags, UPDATE_AVAILABLE, p.available);
SET_FLAG(p.v.flags, UPDATE_INSTALLED, p.installed);
SET_FLAG(p.v.flags, UPDATE_OBSOLETE, p.obsolete);
SET_FLAG(p.v.flags, UPDATE_PROTECTED, p.protected);
SET_FLAG(p.v.flags, UPDATE_INCOMPLETE, p.incomplete);
r = sd_json_variant_format(contents_json, 0, &v.contents_json);
r = sd_json_variant_format(p.contents_json, 0, &p.v.contents_json);
if (r < 0)
return log_error_errno(r, "Failed to format JSON for contents: %m");
*ret = TAKE_STRUCT(v);
*ret = TAKE_STRUCT(p.v);
return 0;
}

View File

@ -1141,6 +1141,18 @@ TEST(ASSERT) {
ASSERT_SIGNAL(ASSERT_OK_ERRNO(-1), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ERRNO(-ENOANO), SIGABRT);
ASSERT_OK_ZERO_ERRNO(0);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(1), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(255), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(-1), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(-ENOANO), SIGABRT);
ASSERT_OK_EQ_ERRNO(0, 0);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(1, 0), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(255, 5), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(-1, 0), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(-ENOANO, 0), SIGABRT);
ASSERT_FAIL(-ENOENT);
ASSERT_FAIL(-EPERM);
ASSERT_SIGNAL(ASSERT_FAIL(0), SIGABRT);

View File

@ -54,46 +54,51 @@ static void test_pid_get_comm_one(pid_t pid) {
xsprintf(path, "/proc/"PID_FMT"/comm", pid);
if (stat(path, &st) == 0) {
assert_se(pid_get_comm(pid, &a) >= 0);
ASSERT_OK(pid_get_comm(pid, &a));
log_info("PID"PID_FMT" comm: '%s'", pid, a);
} else
log_warning("%s not exist.", path);
assert_se(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c) >= 0);
ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
assert_se(pid_get_cmdline(pid, 8, 0, &d) >= 0);
ASSERT_OK(pid_get_cmdline(pid, 8, 0, &d));
log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
free(d);
assert_se(pid_get_cmdline(pid, 1, 0, &d) >= 0);
ASSERT_OK(pid_get_cmdline(pid, 1, 0, &d));
log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
r = get_process_ppid(pid, &e);
assert_se(pid == 1 ? r == -EADDRNOTAVAIL : r >= 0);
if (pid == 1)
ASSERT_ERROR(r, EADDRNOTAVAIL);
else
ASSERT_OK(r);
if (r >= 0) {
log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
assert_se(e > 0);
ASSERT_GT(e, 0);
}
assert_se(pid_is_kernel_thread(pid) == 0 || pid != 1);
ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
r = get_process_exe(pid, &f);
assert_se(r >= 0 || r == -EACCES);
if (r != -EACCES)
ASSERT_OK(r);
log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
assert_se(pid_get_uid(pid, &u) == 0);
ASSERT_OK_ZERO(pid_get_uid(pid, &u));
log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
assert_se(get_process_gid(pid, &g) == 0);
ASSERT_OK_ZERO(get_process_gid(pid, &g));
log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
r = get_process_environ(pid, &env);
assert_se(r >= 0 || r == -EACCES);
if (r != -EACCES)
ASSERT_OK(r);
log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
if (!detect_container())
assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
if (!detect_container() && pid == 1)
ASSERT_ERROR(get_ctty_devnr(pid, &h), ENXIO);
(void) getenv_for_pid(pid, "PATH", &i);
log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
@ -136,14 +141,14 @@ static void test_pid_get_cmdline_one(pid_t pid) {
r = pid_get_cmdline_strv(pid, 0, &strv_a);
if (r >= 0)
assert_se(joined = strv_join(strv_a, "\", \""));
ASSERT_NOT_NULL(joined = strv_join(strv_a, "\", \""));
log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
joined = mfree(joined);
r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
if (r >= 0)
assert_se(joined = strv_join(strv_b, "\", \""));
ASSERT_NOT_NULL(joined = strv_join(strv_b, "\", \""));
log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
}
@ -151,13 +156,13 @@ TEST(pid_get_cmdline) {
_cleanup_closedir_ DIR *d = NULL;
int r;
assert_se(proc_dir_open(&d) >= 0);
ASSERT_OK(proc_dir_open(&d));
for (;;) {
pid_t pid;
r = proc_dir_read(d, &pid);
assert_se(r >= 0);
ASSERT_OK(r);
if (r == 0) /* EOF */
break;
@ -171,8 +176,8 @@ static void test_pid_get_comm_escape_one(const char *input, const char *output)
log_debug("input: <%s> — output: <%s>", input, output);
assert_se(prctl(PR_SET_NAME, input) >= 0);
assert_se(pid_get_comm(0, &n) >= 0);
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, input));
ASSERT_OK(pid_get_comm(0, &n));
log_debug("got: <%s>", n);
@ -182,7 +187,7 @@ static void test_pid_get_comm_escape_one(const char *input, const char *output)
TEST(pid_get_comm_escape) {
_cleanup_free_ char *saved = NULL;
assert_se(pid_get_comm(0, &saved) >= 0);
ASSERT_OK(pid_get_comm(0, &saved));
test_pid_get_comm_escape_one("", "");
test_pid_get_comm_escape_one("foo", "foo");
@ -195,62 +200,62 @@ TEST(pid_get_comm_escape) {
test_pid_get_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
test_pid_get_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
assert_se(prctl(PR_SET_NAME, saved) >= 0);
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
}
TEST(pid_is_unwaited) {
pid_t pid;
pid = fork();
assert_se(pid >= 0);
ASSERT_OK_ERRNO(pid);
if (pid == 0) {
_exit(EXIT_SUCCESS);
} else {
int status;
assert_se(waitpid(pid, &status, 0) == pid);
assert_se(pid_is_unwaited(pid) == 0);
ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
ASSERT_OK_ZERO(pid_is_unwaited(pid));
}
assert_se(pid_is_unwaited(getpid_cached()) > 0);
assert_se(pid_is_unwaited(-1) < 0);
ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
ASSERT_FAIL(pid_is_unwaited(-1));
}
TEST(pid_is_alive) {
pid_t pid;
pid = fork();
assert_se(pid >= 0);
ASSERT_OK_ERRNO(pid);
if (pid == 0) {
_exit(EXIT_SUCCESS);
} else {
int status;
assert_se(waitpid(pid, &status, 0) == pid);
assert_se(pid_is_alive(pid) == 0);
ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
ASSERT_OK_ZERO(pid_is_alive(pid));
}
assert_se(pid_is_alive(getpid_cached()) > 0);
assert_se(pid_is_alive(-1) < 0);
ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
ASSERT_FAIL(pid_is_alive(-1));
}
TEST(personality) {
assert_se(personality_to_string(PER_LINUX));
assert_se(!personality_to_string(PERSONALITY_INVALID));
ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX);
assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX);
ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX)), (unsigned long) PER_LINUX);
ASSERT_EQ(personality_from_string(architecture_to_string(native_architecture())), (unsigned long) PER_LINUX);
#ifdef __x86_64__
ASSERT_STREQ(personality_to_string(PER_LINUX), "x86-64");
ASSERT_STREQ(personality_to_string(PER_LINUX32), "x86");
assert_se(personality_from_string("x86-64") == PER_LINUX);
assert_se(personality_from_string("x86") == PER_LINUX32);
assert_se(personality_from_string("ia64") == PERSONALITY_INVALID);
assert_se(personality_from_string(NULL) == PERSONALITY_INVALID);
ASSERT_EQ(personality_from_string("x86-64"), (unsigned long) PER_LINUX);
ASSERT_EQ(personality_from_string("x86"), (unsigned long) PER_LINUX32);
ASSERT_EQ(personality_from_string("ia64"), PERSONALITY_INVALID);
ASSERT_EQ(personality_from_string(NULL), PERSONALITY_INVALID);
assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32)), (unsigned long) PER_LINUX32);
#endif
}
@ -288,30 +293,31 @@ TEST(pid_get_cmdline_harder) {
(void) wait_for_terminate(pid, &si);
assert_se(si.si_code == CLD_EXITED);
assert_se(si.si_status == 0);
ASSERT_EQ(si.si_code, CLD_EXITED);
ASSERT_OK_ZERO(si.si_status);
return;
}
assert_se(pid == 0);
ASSERT_OK_ZERO(pid);
r = detach_mount_namespace();
if (r < 0) {
log_warning_errno(r, "detach mount namespace failed: %m");
assert_se(ERRNO_IS_PRIVILEGE(r));
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
return;
}
fd = mkostemp(path, O_CLOEXEC);
assert_se(fd >= 0);
ASSERT_OK_ERRNO(fd);
/* Note that we don't unmount the following bind-mount at the end of the test because the kernel
* will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
/* This happens under selinux… Abort the test in this case. */
log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
assert_se(IN_SET(errno, EPERM, EACCES));
ASSERT_TRUE(IN_SET(errno, EPERM, EACCES));
return;
}
@ -320,197 +326,197 @@ TEST(pid_get_cmdline_harder) {
if (setrlimit(RLIMIT_STACK, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
log_warning("Testing without RLIMIT_STACK=infinity");
assert_se(unlink(path) >= 0);
ASSERT_OK_ERRNO(unlink(path));
assert_se(prctl(PR_SET_NAME, "testa") >= 0);
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) == -ENOENT);
ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[testa]");
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
line = mfree(line);
assert_se(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "");
line = mfree(line);
assert_se(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "");
line = mfree(line);
assert_se(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[t…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[te…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[tes…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[test…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[testa]");
line = mfree(line);
assert_se(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[testa]");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("[testa]")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
args = strv_free(args);
/* Test with multiple arguments that don't require quoting */
assert_se(write(fd, "foo\0bar", 8) == 8);
ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar");
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "foo bar");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("foo", "bar")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
args = strv_free(args);
assert_se(write(fd, "quux", 4) == 4);
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) >= 0);
ASSERT_OK_EQ_ERRNO(write(fd, "quux", 4), 4);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "");
line = mfree(line);
assert_se(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "f…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "fo…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo …");
line = mfree(line);
assert_se(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo b…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo ba…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar …");
line = mfree(line);
assert_se(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar q…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar qu…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
args = strv_free(args);
assert_se(ftruncate(fd, 0) >= 0);
assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
ASSERT_OK_ERRNO(ftruncate(fd, 0));
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) == -ENOENT);
ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbbb cccc]");
line = mfree(line);
assert_se(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbb…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbbb…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbbb …");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
args = strv_free(args);
/* Test with multiple arguments that do require quoting */
@ -520,24 +526,24 @@ TEST(pid_get_cmdline_harder) {
#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
assert_se(lseek(fd, SEEK_SET, 0) == 0);
assert_se(write(fd, CMDLINE1, sizeof CMDLINE1) == sizeof CMDLINE1);
assert_se(ftruncate(fd, sizeof CMDLINE1) == 0);
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT1);
ASSERT_STREQ(line, EXPECT1);
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT1p);
ASSERT_STREQ(line, EXPECT1p);
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, 0, &args) >= 0);
assert_se(strv_equal(args, EXPECT1v));
ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
ASSERT_TRUE(strv_equal(args, EXPECT1v));
args = strv_free(args);
#define CMDLINE2 "foo\0\1\2\3\0\0"
@ -545,24 +551,24 @@ TEST(pid_get_cmdline_harder) {
#define EXPECT2p "foo $'\\001\\002\\003'"
#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
assert_se(lseek(fd, SEEK_SET, 0) == 0);
assert_se(write(fd, CMDLINE2, sizeof CMDLINE2) == sizeof CMDLINE2);
assert_se(ftruncate(fd, sizeof CMDLINE2) == 0);
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT2);
ASSERT_STREQ(line, EXPECT2);
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT2p);
ASSERT_STREQ(line, EXPECT2p);
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, 0, &args) >= 0);
assert_se(strv_equal(args, EXPECT2v));
ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
ASSERT_TRUE(strv_equal(args, EXPECT2v));
args = strv_free(args);
safe_close(fd);
@ -577,10 +583,11 @@ TEST(getpid_cached) {
b = getpid_cached();
c = getpid();
assert_se(a == b && a == c);
ASSERT_EQ(a, b);
ASSERT_EQ(a, c);
child = fork();
assert_se(child >= 0);
ASSERT_OK_ERRNO(child);
if (child == 0) {
/* In child */
@ -588,7 +595,8 @@ TEST(getpid_cached) {
b = getpid_cached();
c = getpid();
assert_se(a == b && a == c);
ASSERT_EQ(a, b);
ASSERT_EQ(a, c);
_exit(EXIT_SUCCESS);
}
@ -596,11 +604,13 @@ TEST(getpid_cached) {
e = getpid_cached();
f = getpid();
assert_se(a == d && a == e && a == f);
ASSERT_EQ(a, d);
ASSERT_EQ(a, e);
ASSERT_EQ(a, f);
assert_se(wait_for_terminate(child, &si) >= 0);
assert_se(si.si_status == 0);
assert_se(si.si_code == CLD_EXITED);
ASSERT_OK(wait_for_terminate(child, &si));
ASSERT_EQ(si.si_status, 0);
ASSERT_EQ(si.si_code, CLD_EXITED);
}
TEST(getpid_measure) {
@ -635,7 +645,7 @@ TEST(safe_fork) {
BLOCK_SIGNALS(SIGCHLD);
r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
assert_se(r >= 0);
ASSERT_OK(r);
if (r == 0) {
/* child */
@ -644,43 +654,42 @@ TEST(safe_fork) {
_exit(88);
}
assert_se(wait_for_terminate(pid, &status) >= 0);
assert_se(status.si_code == CLD_EXITED);
assert_se(status.si_status == 88);
ASSERT_OK(wait_for_terminate(pid, &status));
ASSERT_EQ(status.si_code, CLD_EXITED);
ASSERT_EQ(status.si_status, 88);
}
TEST(pid_to_ptr) {
assert_se(PTR_TO_PID(NULL) == 0);
ASSERT_EQ(PTR_TO_PID(NULL), 0);
ASSERT_NULL(PID_TO_PTR(0));
assert_se(PTR_TO_PID(PID_TO_PTR(1)) == 1);
assert_se(PTR_TO_PID(PID_TO_PTR(2)) == 2);
assert_se(PTR_TO_PID(PID_TO_PTR(-1)) == -1);
assert_se(PTR_TO_PID(PID_TO_PTR(-2)) == -2);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MAX)) == INT16_MAX);
assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MIN)) == INT16_MIN);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MAX)) == INT32_MAX);
assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MIN)) == INT32_MIN);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
}
static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
assert_se(ioprio_class_from_string(val) == expected);
ASSERT_EQ(ioprio_class_from_string(val), expected);
if (expected >= 0) {
_cleanup_free_ char *s = NULL;
unsigned ret;
int combined;
assert_se(ioprio_class_to_string_alloc(expected, &s) == 0);
ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
/* We sometimes get a class number and sometimes a name back */
assert_se(streq(s, val) ||
safe_atou(val, &ret) == 0);
ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
/* Make sure normalization works, i.e. NONE → BE gets normalized */
combined = ioprio_normalize(ioprio_prio_value(expected, 0));
assert_se(ioprio_prio_class(combined) == normalized);
assert_se(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
ASSERT_EQ(ioprio_prio_class(combined), normalized);
ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
}
}
@ -701,8 +710,8 @@ TEST(setpriority_closest) {
int r;
r = safe_fork("(test-setprio)",
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
assert_se(r >= 0);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
ASSERT_OK(r);
if (r == 0) {
bool full_test;
@ -713,16 +722,21 @@ TEST(setpriority_closest) {
if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
/* If this fails we are probably unprivileged or in a userns of some kind, let's skip
* the full test */
assert_se(ERRNO_IS_PRIVILEGE(errno));
if (!ERRNO_IS_PRIVILEGE(errno))
ASSERT_OK_ERRNO(-1);
full_test = false;
} else {
/* However, if the hard limit was above 30, setrlimit would succeed unprivileged, so
* check if the UID/GID can be changed before enabling the full test. */
if (setresgid(GID_NOBODY, GID_NOBODY, GID_NOBODY) < 0) {
assert_se(ERRNO_IS_PRIVILEGE(errno));
/* If the nobody user does not exist (user namespace) we get EINVAL. */
if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
ASSERT_OK_ERRNO(-1);
full_test = false;
} else if (setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) < 0) {
assert_se(ERRNO_IS_PRIVILEGE(errno));
/* If the nobody user does not exist (user namespace) we get EINVAL. */
if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
ASSERT_OK_ERRNO(-1);
full_test = false;
} else
full_test = true;
@ -730,61 +744,69 @@ TEST(setpriority_closest) {
errno = 0;
p = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0);
ASSERT_EQ(errno, 0);
/* It should always be possible to set our nice level to the current one */
assert_se(setpriority_closest(p) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(p));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
ASSERT_EQ(errno, 0);
ASSERT_EQ(p, q);
/* It should also be possible to set the nice level to one higher */
if (p < PRIO_MAX-1) {
assert_se(setpriority_closest(++p) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(++p));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
ASSERT_EQ(errno, 0);
ASSERT_EQ(p, q);
}
/* It should also be possible to set the nice level to two higher */
if (p < PRIO_MAX-1) {
assert_se(setpriority_closest(++p) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(++p));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
ASSERT_EQ(errno, 0);
ASSERT_EQ(p, q);
}
if (full_test) {
/* These two should work, given the RLIMIT_NICE we set above */
assert_se(setpriority_closest(-10) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(-10));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -10);
assert_se(setpriority_closest(-9) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(-9));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -9);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -9);
/* This should succeed but should be clamped to the limit */
assert_se(setpriority_closest(-11) == 0);
ASSERT_OK_ZERO(setpriority_closest(-11));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -10);
assert_se(setpriority_closest(-8) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(-8));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -8);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -8);
/* This should succeed but should be clamped to the limit */
assert_se(setpriority_closest(-12) == 0);
ASSERT_OK_ZERO(setpriority_closest(-12));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -10);
}
_exit(EXIT_SUCCESS);
@ -795,10 +817,10 @@ TEST(get_process_ppid) {
uint64_t limit;
int r;
assert_se(get_process_ppid(1, NULL) == -EADDRNOTAVAIL);
ASSERT_ERROR(get_process_ppid(1, NULL), EADDRNOTAVAIL);
/* the process with the PID above the global limit definitely doesn't exist. Verify that */
assert_se(procfs_get_pid_max(&limit) >= 0);
ASSERT_OK(procfs_get_pid_max(&limit));
log_debug("kernel.pid_max = %"PRIu64, limit);
if (limit < INT_MAX) {
@ -817,10 +839,10 @@ TEST(get_process_ppid) {
break;
}
assert_se(r >= 0);
ASSERT_OK(r);
assert_se(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1) >= 0);
assert_se(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2) >= 0);
ASSERT_OK(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
ASSERT_OK(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2);
@ -831,19 +853,20 @@ TEST(get_process_ppid) {
TEST(set_oom_score_adjust) {
int a, b, r;
assert_se(get_oom_score_adjust(&a) >= 0);
ASSERT_OK(get_oom_score_adjust(&a));
r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r));
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
if (r >= 0) {
assert_se(get_oom_score_adjust(&b) >= 0);
assert_se(b == OOM_SCORE_ADJ_MIN);
ASSERT_OK(get_oom_score_adjust(&b));
ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
}
assert_se(set_oom_score_adjust(a) >= 0);
assert_se(get_oom_score_adjust(&b) >= 0);
assert_se(b == a);
ASSERT_OK(set_oom_score_adjust(a));
ASSERT_OK(get_oom_score_adjust(&b));
ASSERT_EQ(b, a);
}
static void* dummy_thread(void *p) {
@ -851,10 +874,10 @@ static void* dummy_thread(void *p) {
char x;
/* let main thread know we are ready */
assert_se(write(fd, &(const char) { 'x' }, 1) == 1);
ASSERT_OK_EQ_ERRNO(write(fd, &(const char) { 'x' }, 1), 1);
/* wait for the main thread to tell us to shut down */
assert_se(read(fd, &x, 1) == 1);
ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
return NULL;
}
@ -862,38 +885,42 @@ TEST(get_process_threads) {
int r;
/* Run this test in a child, so that we can guarantee there's exactly one thread around in the child */
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_WAIT|FORK_LOG, NULL);
assert_se(r >= 0);
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
ASSERT_OK(r);
if (r == 0) {
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
pthread_t t, tt;
char x;
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd) >= 0);
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd) >= 0);
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd));
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd));
assert_se(get_process_threads(0) == 1);
assert_se(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])) == 0);
assert_se(read(pfd[1], &x, 1) == 1);
assert_se(get_process_threads(0) == 2);
assert_se(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])) == 0);
assert_se(read(ppfd[1], &x, 1) == 1);
assert_se(get_process_threads(0) == 3);
ASSERT_OK_EQ(get_process_threads(0), 1);
ASSERT_OK_ZERO_ERRNO(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])));
ASSERT_OK_EQ_ERRNO(read(pfd[1], &x, 1), 1);
ASSERT_OK_EQ(get_process_threads(0), 2);
ASSERT_OK_ZERO_ERRNO(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])));
ASSERT_OK_EQ_ERRNO(read(ppfd[1], &x, 1), 1);
ASSERT_OK_EQ(get_process_threads(0), 3);
assert_se(write(pfd[1], &(const char) { 'x' }, 1) == 1);
assert_se(pthread_join(t, NULL) == 0);
ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
/* the value reported via /proc/ is decreased asynchronously, and there appears to be no nice
* way to sync on it. Hence we do the weak >= 2 check, even though == 2 is what we'd actually
* like to check here */
assert_se(get_process_threads(0) >= 2);
r = get_process_threads(0);
ASSERT_OK(r);
ASSERT_GE(r, 2);
assert_se(write(ppfd[1], &(const char) { 'x' }, 1) == 1);
assert_se(pthread_join(tt, NULL) == 0);
ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
/* similar here */
assert_se(get_process_threads(0) >= 1);
r = get_process_threads(0);
ASSERT_OK(r);
ASSERT_GE(r, 1);
_exit(EXIT_SUCCESS);
}
@ -902,17 +929,17 @@ TEST(get_process_threads) {
TEST(is_reaper_process) {
int r;
r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* child */
assert_se(is_reaper_process() == 0);
ASSERT_OK_ZERO(is_reaper_process());
_exit(EXIT_SUCCESS);
}
r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* child */
@ -923,25 +950,25 @@ TEST(is_reaper_process) {
}
}
r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* grandchild, which is PID1 in a pidns */
assert_se(getpid_cached() == 1);
assert_se(is_reaper_process() > 0);
ASSERT_OK_EQ(getpid_cached(), 1);
ASSERT_OK_POSITIVE(is_reaper_process());
_exit(EXIT_SUCCESS);
}
_exit(EXIT_SUCCESS);
}
r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* child */
assert_se(make_reaper_process(true) >= 0);
ASSERT_OK(make_reaper_process(true));
assert_se(is_reaper_process() > 0);
ASSERT_OK_POSITIVE(is_reaper_process());
_exit(EXIT_SUCCESS);
}
}
@ -949,22 +976,22 @@ TEST(is_reaper_process) {
TEST(pid_get_start_time) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
assert_se(pidref_set_self(&pidref) >= 0);
ASSERT_OK(pidref_set_self(&pidref));
usec_t start_time;
assert_se(pidref_get_start_time(&pidref, &start_time) >= 0);
ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
log_info("our starttime: " USEC_FMT, start_time);
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
assert_se(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &child) >= 0);
ASSERT_OK(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG, &child));
usec_t start_time2;
assert_se(pidref_get_start_time(&child, &start_time2) >= 0);
ASSERT_OK(pidref_get_start_time(&child, &start_time2));
log_info("child starttime: " USEC_FMT, start_time2);
assert_se(start_time2 >= start_time);
ASSERT_GE(start_time2, start_time);
}
static int intro(void) {

View File

@ -259,7 +259,7 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
if (arg_graceful && !tpm2_is_fully_supported()) {
log_notice("No complete TPM2 support detected, exiting gracefully.");
return EXIT_SUCCESS;
}

View File

@ -288,7 +288,7 @@ static int verb_info(int argc, char *argv[], void *userdata) {
pager_open(arg_pager_flags);
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
static const struct sd_json_dispatch_field dispatch_table[] = {
static const sd_json_dispatch_field dispatch_table[] = {
{ "vendor", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, vendor), SD_JSON_MANDATORY },
{ "product", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, product), SD_JSON_MANDATORY },
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, version), SD_JSON_MANDATORY },
@ -380,12 +380,12 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
const struct sd_json_dispatch_field dispatch_table[] = {
{ "interfaces", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, PTR_TO_SIZE(&auto_interfaces), SD_JSON_MANDATORY },
static const sd_json_dispatch_field dispatch_table[] = {
{ "interfaces", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, 0, SD_JSON_MANDATORY },
{}
};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, NULL);
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &auto_interfaces);
if (r < 0)
return r;
@ -412,7 +412,7 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
return r;
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF) || list_methods) {
static const struct sd_json_dispatch_field dispatch_table[] = {
static const sd_json_dispatch_field dispatch_table[] = {
{ "description", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
{}
};

View File

@ -4,5 +4,6 @@ integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'storage': 'persistent',
'vm' : true,
},
]

View File

@ -21,6 +21,9 @@ at_exit() {
trap at_exit EXIT
systemctl unmask systemd-networkd.service
systemctl start systemd-networkd.service
export NETWORK_NAME="10-networkctl-test-$RANDOM.network"
export NETDEV_NAME="10-networkctl-test-$RANDOM.netdev"
export LINK_NAME="10-networkctl-test-$RANDOM.link"
@ -75,15 +78,6 @@ cmp "+4" "/etc/systemd/network/${NETWORK_NAME}.d/test.conf"
networkctl cat "$NETWORK_NAME" | grep '^# ' |
cmp - <(printf '%s\n' "# /etc/systemd/network/$NETWORK_NAME" "# /etc/systemd/network/${NETWORK_NAME}.d/test.conf")
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
[NetDev]
Name=test2
Kind=dummy
EOF
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
cat >"/usr/lib/systemd/network/$LINK_NAME" <<EOF
[Match]
OriginalName=test2
@ -95,13 +89,23 @@ EOF
SYSTEMD_LOG_LEVEL=debug EDITOR='true' script -ec 'networkctl edit "$LINK_NAME"' /dev/null
cmp "/usr/lib/systemd/network/$LINK_NAME" "/etc/systemd/network/$LINK_NAME"
# Test links
systemctl unmask systemd-networkd
systemctl stop systemd-networkd
# The interface test2 does not exist, hence the below do not work.
(! networkctl cat @test2)
(! networkctl cat @test2:netdev)
(! networkctl cat @test2:link)
(! networkctl cat @test2:network)
systemctl start systemd-networkd
# create .netdev file at last, otherwise, the .link file will not be applied to the interface.
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
[NetDev]
Name=test2
Kind=dummy
EOF
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
# wait for the interface being created and configured.
SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-networkd-wait-online -i test2:carrier --timeout 20
networkctl cat @test2:network | cmp - <(networkctl cat "$NETWORK_NAME")