rfkill: ['systemd-rfkill']
rpm: ['rpm scriptlets']
run: ['systemd-run']
- sd-boot: ['bootctl', 'systemd-boot', 'systemd-stub']
+ sd-boot/sd-stub/bootctl: ['bootctl', 'systemd-boot', 'systemd-stub']
sysctl: ['systemd-sysctl']
sysext: ['systemd-sysext']
systemctl: ['systemctl']
runs-on: ubuntu-22.04
if: github.repository == 'systemd/systemd'
env:
- COVERITY_SCAN_BRANCH_PATTERN: "${{ github.ref}}"
- COVERITY_SCAN_NOTIFICATION_EMAIL: ""
- COVERITY_SCAN_PROJECT_NAME: "${{ github.repository }}"
- # Set in repo settings -> secrets -> repository secrets
+ # Set in repo settings -> secrets -> actions
COVERITY_SCAN_TOKEN: "${{ secrets.COVERITY_SCAN_TOKEN }}"
- CURRENT_REF: "${{ github.ref }}"
+ COVERITY_SCAN_NOTIFICATION_EMAIL: "${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}"
steps:
- name: Repository checkout
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
- - name: Set the $COVERITY_SCAN_NOTIFICATION_EMAIL env variable
- run: echo "COVERITY_SCAN_NOTIFICATION_EMAIL=$(git log -1 ${{ github.sha }} --pretty=\"%aE\")" >> "$GITHUB_ENV"
- - name: Install Coverity tools
- run: tools/get-coverity.sh
# Reuse the setup phase of the unit test script to avoid code duplication
- name: Install build dependencies
run: sudo -E .github/workflows/unit_tests.sh SETUP
- # Preconfigure with meson to prevent Coverity from capturing meson metadata
- - name: Preconfigure the build directory
- run: meson cov-build -Dman=false
- - name: Build
- run: tools/coverity.sh build
- - name: Upload the results
- run: tools/coverity.sh upload
+ - name: Build & upload the results
+ run: tools/coverity.sh
--- /dev/null
+---
+# https://github.com/redhat-plumbers-in-action/differential-shellcheck#readme
+
+name: Differential ShellCheck
+on:
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ contents: read
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+
+ permissions:
+ security-events: write
+ pull-requests: write
+
+ steps:
+ - name: Repository checkout
+ uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
+ with:
+ fetch-depth: 0
+
+ - name: Differential ShellCheck
+ uses: redhat-plumbers-in-action/differential-shellcheck@60360c0fb283149ed03ad16b66257a967c3e5231
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
# missing shebangs)
# - .*\.(in|SKELETON) - all template/skeleton files
# except kernel-install
- # - tools/coverity\.sh - external file (with some modifications)
- FILTER_REGEX_EXCLUDE: .*/(man/.*|([^k]|k(k|ek)*([^ek]|e[^kr]))*(k(k|ek)*e?)?\.(in|SKELETON)|tools/coverity\.sh)$
+ FILTER_REGEX_EXCLUDE: .*/(man/.*|([^k]|k(k|ek)*([^ek]|e[^kr]))*(k(k|ek)*e?)?\.(in|SKELETON))$
VALIDATE_ALL_CODEBASE: false
VALIDATE_BASH: true
VALIDATE_GITHUB_ACTIONS: true
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- - uses: systemd/mkosi@104483c479df5673e5ab52a16ca9484ee5cef3fd
+ - uses: systemd/mkosi@f37c19e7217a41c52d9a9a8769e98496255e2e2d
- name: Install
run: sudo apt-get update && sudo apt-get install --no-install-recommends python3-pexpect python3-jinja2
/mkosi.default.d/**/*local*.conf
/tags
.dir-locals-2.el
+.vscode/
UBUNTU_RELEASE="$(lsb_release -cs)"
create_container() {
- # Create autopkgtest LXC image; this sometimes fails with "Unable to fetch
- # GPG key from keyserver", so retry a few times with different keyservers.
- for keyserver in "keys.openpgp.org" "" "keyserver.ubuntu.com" "keys.gnupg.net"; do
- for retry in {1..5}; do
- sudo lxc-create -n "$CONTAINER" -t download -- -d "$DISTRO" -r "$RELEASE" -a "$ARCH" ${keyserver:+--keyserver "$keyserver"} && break 2
- sleep $((retry*retry))
- done
- done
+ sudo lxc-create -n "$CONTAINER" -t download -- -d "$DISTRO" -r "$RELEASE" -a "$ARCH"
# unconfine the container, otherwise some tests fail
echo 'lxc.apparmor.profile = unconfined' | sudo tee -a "/var/lib/lxc/$CONTAINER/config"
# now build the package and run the tests
rm -rf "$ARTIFACTS_DIR"
# autopkgtest exits with 2 for "some tests skipped", accept that
- "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS=noudeb \
- --env TEST_UPSTREAM=1 ../systemd_*.dsc \
- -o "$ARTIFACTS_DIR" \
- -- lxc -s "$CONTAINER" \
+ sudo "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS=noudeb \
+ --env TEST_UPSTREAM=1 ../systemd_*.dsc \
+ -o "$ARTIFACTS_DIR" \
+ -- lxc -s "$CONTAINER" \
|| [ $? -eq 2 ]
;;
*)
systemd System and Service Manager
-CHANGES WITH 252:
+CHANGES WITH 252 in spe:
Announcement of Future Feature Removal
sooner rather than later, if you haven't done so yet. Most of Linux
userspace has been ported over already.
+ New features:
+
+ * systemd-measure is a new helper to precalculate PCR measurements
+ to make it easier to set TPM2 policies.
+
+ Changes in systemd itself, i.e. the manager, and units
+
+ * The cpu controller is delegated to user manager units, and CPUWeight=
+ settings are applied to the top-level user slice units (app.slice,
+ background.slice, session.slice). This provides a degree of resource
+ isolation between different user services competing for the CPU.
+
+ * Systemd can optionally do a full preset in the "first boot" condition
+ (instead of just enable-only). This behaviour is controlled by the
+ compile-time option -Dfirst-boot-full-preset=. Right now it defaults
+ to 'false', but the plan is to switch it to 'true' for the subsequent
+ release.
+
+ * Systemd will set the taint flag 'support-ended' if it detects that
+ the os image is past its end-of-support date.
+
+ * Two new settings ConditionCredential= and AssertCredential= can
+ be used to skip or fail units if a certain credential is not provided.
+
+ * ConditionMemory= accepts size suffixes.
+
+ * DefaultSmackProcessLabel= can be used in system.conf and user.conf
+ to specify the smack label to use when not specified in a unit file.
+
+ * DefaultDeviceTimeoutSec= can be used system.conf and user.conf
+ to specify the default timeout for devices.
+
+ * C.UTF-8 is used as the default locale if nothing else has been configured.
+
+ Changes in sd-boot, bootctl, and the Boot Loader Specification:
+
+ * The Boot Loader Specification has been cleaned up and clarified.
+ Various corner cases in version string comparisons have been fixed
+ (e.g. comparisons for empty strings). Boot counting is now part of
+ the main specification.
+
+ * New PCRs measurements are set during boot: PCR 11 for the the
+ kernel+initrd combo, PCR 13 for any sysext images.
+
+ * The UEFI monotonic boot counter is now included in the random seed,
+ providing some additional entropy.
+
+ * Booting in EFI mixed mode (a 64-bit kernel over 32-bit UEFI firmware)
+ is now supported.
+
+ * bootctl gained a bunch of new options: '--all-architectures' to
+ install binaries for all supported EFI architectures, '--root=' and
+ '--image=' options to operate on a directory or disk image, and
+ '--install-source=' to specify the source for binaries to install.
+
+ * The sd-boot stub exports a StubFeatures flag, which is used by
+ bootctl to show features supported by the stub that was used to boot.
+
+ Changes in the hardware database:
+
+ * 'systemd-hwdb query' now supports the '--root' option.
+
+ Changes in systemctl:
+
+ * systemctl now supports '--state' and '--type' options for the 'show'
+ and 'status' verbs.
+
+ * systemctl gained a new verb 'list-automounts' to list automount
+ points.
+
+ Changes in systemd-networkd:
+
+ * networkd can set Linux NetLabel labels for integration with the
+ network control in security modules via a new NetLabel= option.
+
+ * networkd gained new options NFTSet=, IPv4NFTSet=, IPv6NFTSet= that
+ take names of nft sets as arguments. It will automatically add rules
+ for the subnets configured for an interface to those sets.
+
+ * The RapidCommit= is (re-)introduced to enable faster configuration
+ via DHCPv6 (RFC 3315).
+
+ Changes in systemd-nspawn:
+
+ * The --bind= and --overlay= options now support relative paths.
+
+ Changes in libsystemd and other libraries:
+
+ * libsystemd now exports the sd-netlink interface that provides
+ functions to send/receive/parse netlink and rtnl messages.
+
+ * libsystemd now exports sd_bus_error_setfv (a convenience function for
+ setting bus errors), sd_id128_string_equal (a convenience function
+ for identifier comparisons), sd_bus_message_read_strv_extend (a
+ function to incrementally read string arrays).
+
+ * Private shared libraries (libsystemd-shared-nnn.so,
+ libsystemd-core-nnn.so) are now installed into arch-specific
+ directories to allow multi-arch installs.
+
+ Changes in other components:
+
+ * sysusers and tmpfiles configuration can now be provided via the
+ credential mechanism.
+
+ * tmpfiles can read file contents to write from a credential (and a new
+ modifier char '^' to specify that the argument is a credential name).
+ This mechanism is used to automatically populate /etc/motd, /etc/issue,
+ and /etc/hosts from credentials.
+
+ * systemd-analyze gained a new verb 'compare-versions' that implements
+ comparisons for versions strings (similarly to 'rpmdev-vercmp' and
+ 'dpkg --compare-versions').
+
+ * The pkgconfig and rpm macros files now export the directory for user
+ units as 'user_tmpfiles_dir' and '_user_tmpfilesdir'.
+
+ * Detection of Parallels and KubeVirt virtualization has been improved.
+
+ * os-release gained a new field SUPPORT_END=YYYY-MM-DD to inform the
+ user when their system will become unsupported.
+
+ * When performing suspend-then-hibernate, the system will estimate the
+ discharge rate and use that to set the delay until hibernation, and
+ will hibernate immediately instead of suspending when running from a
+ battery and the capacity is below 5%.
+
+ * systemd-sysctl gained a '--strict' option to fail when a sysctl
+ setting is unknown to the kernel.
+
+ * machinectl supports '--force' for the 'copy-to' and 'copy-from'
+ verbs.
+
+ * openssl is the default crypto backend for systemd-resolved. (gnutls
+ is still supported.)
+
+ Experimental features:
+
+ * BPF programs can now be compiled with bpf-gcc.
+
+ * sd-boot can automatically enroll SecureBoot keys from files found on
+ the ESP. This enrollment can be either automatic ('force' mode) or
+ controlled by the user ('manual' mode).
+
+ – Somewhere, sometime
+
+
CHANGES WITH 251:
Backwards-incompatible changes:
the seed from there already, if EFI_RNG_PROTOCOL is not implemented by
firmware.
+* sd-boot: include domain specific hash string in hash function for random seed
+ plus sizes of everything. also include DMI/SMBIOS blob
+
+* accept a random seed via DMI/SMBIOS vendor string that is credited to the
+ kernel RNG, as cheap alternative to virtio-rng
+
* sd-stub: invoke random seed logic the same way as in sd-boot, except if
random seed EFI variable is already set. That way, the variable set will be
set in all cases: if you just use sd-stub, or just sd-boot, or both.
* fstab-generator: default to tmpfs-as-root if only usr= is specified on the kernel cmdline
-* initrd-parse-etc.service: can we skip daemon-reload if /sysroot/etc/fstab is missing?
- Note that we start initrd-fs.target and initrd-cleanup.target there, so a straightforward
- ConditionPathExists= is not enough.
-
* docs: bring https://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date
* add a job mode that will fail if a transaction would mean stopping
three of these specific switches would set credential `foo` to `bar`.)
Passing credentials via the SMBIOS mechanism is typically preferable over
`fw_cfg` since it is faster and less specific to the chosen VMM
- implementation.
+ implementation. Moreover, `fw_cfg` has a 55 character limitation
+ on names passed that way. So some settings may not fit.
3. Credentials can also be passed into a system via the kernel command line,
via the `systemd.set-credential=` kernel command line option. Note though
# 60-sensor.rules
#
# Match string formats:
+# sensor:<label>:modalias:<parent modalias pattern>:dmi:<dmi pattern>
# sensor:modalias:<parent modalias pattern>:dmi:<dmi pattern>
#
# The device modalias can be seen in the `modalias` file of the sensor parent,
+# and the device label can be seen in the `label` file of the sensor,
# for example:
+# cat /sys/`udevadm info -q path -n /dev/iio:device0`/label
# cat /sys/`udevadm info -q path -n /dev/iio:device0`/../modalias
#
# The full DMI string of the running machine can be read from
#########################################
# Google Chromebooks
#########################################
-sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
-
-# caroline board (Samsung Chromebook Pro) reports itself as svnGoogle
-sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
-# Dell Inspiron Chromebook 14 2-in-1
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnVayne*:*
+# CrOS EC & kernel drivers internally correct for per-board sensor orientations,
+# but they return values in the inverse direction (Android & W3C specs vs HID).
+sensor:modalias:platform:cros-ec-accel:*
+sensor:modalias:platform:cros-ec-accel-legacy:*
+sensor:accel-display:modalias:platform:cros-ec-accel:*
+sensor:accel-display:modalias:platform:cros-ec-accel-legacy:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
-# nocturne board (Google Pixel Slate)
-sensor:modalias:platform:cros-ec-accel:dmi:*Google_Nocturne*:*
- ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
-
-# rammus board (Asus Chromebook Flip C433)
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnRammus*:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
-
-# Lenovo ThinkPad C13 Yoga
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnMorphius*:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+# Base accel reports the same as display when lid angle is 180 degrees (vs 0),
+# so it needs an additional 180 degree rotation around the X axis.
+sensor:accel-base:modalias:platform:cros-ec-accel:*
+sensor:accel-base:modalias:platform:cros-ec-accel-legacy:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
#########################################
# GP-electronic
# This file is part of systemd.
#
# Database for signal analyzers (protocol analyzers, logic analyzers,
-# oscilloscopes, multimeters, bench power supplies, etc.) that should
-# be accessible to the seat owner.
+# oscilloscopes, multimeters, bench power supplies, etc.) or just
+# anything that has to do with electronics and that should be
+# accessible to the seat owner.
#
# Permitted keys:
# Specify if a device is a signal analyzer
# ID_SIGNAL_ANALYZER=1|0
+###########################################################
+# Greaseweazle
+###########################################################
+# Greaseweazle
+usb:v1209p4D69*
+ ID_SIGNAL_ANALYZER=1
+
###########################################################
# Total Phase
###########################################################
'touchpad': ('i8042', 'rmi', 'bluetooth', 'usb'),
'joystick': ('i8042', 'rmi', 'bluetooth', 'usb'),
'keyboard': ('name', ),
- 'sensor': ('modalias', ),
+ 'sensor': ('modalias',
+ 'accel-base',
+ 'accel-display',
+ 'accel-camera',
+ 'proximity-palmrest',
+ 'proximity-palmrest-left',
+ 'proximity-palmrest-right',
+ 'proximity-lap',
+ 'proximity-wifi',
+ 'proximity-lte',
+ 'proximity-wifi-lte',
+ 'proximity-wifi-left',
+ 'proximity-wifi-right',
+ ),
'ieee1394-unit-function' : ('node', ),
'camera': ('usb'),
}
<listitem><para>Install binaries for all supported EFI architectures (this implies <option>--no-variables</option>).</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--efi-boot-option-description=</option></term>
+ <listitem><para>Description of the entry added to the firmware's boot option list. Defaults to <literal>Linux
+ Boot Manager</literal>.</para>
+
+ <para>Using the default entry name <literal>Linux Boot Manager</literal> is generally preferable as only
+ one bootloader installed to a single ESP partition should be used to boot any number of OS installations
+ found on the various disks installed in the system. Specifically distributions should not use this flag
+ to install a branded entry in the boot option list. However in situations with multiple disks, each with
+ their own ESP partition, it can be beneficial to make it easier to identify the bootloader being used in
+ the firmware's boot option menu.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="no-pager"/>
<xi:include href="standard-options.xml" xpointer="json" />
<xi:include href="standard-options.xml" xpointer="help"/>
available to the user.</para>
<programlisting>
- (various (various (various
- timers...) paths...) sockets...) (sound devices)
- | | | |
- v v v v
- timers.target paths.target sockets.target sound.target
- | | |
- \______________ _|_________________/ (bluetooth devices)
- \ / |
- V v
- basic.target bluetooth.target
- |
- __________/ \_______ (smartcard devices)
- / \ |
- | | v
- | v smartcard.target
- v graphical-session-pre.target
- (various user services) | (printers)
- | v |
- | (services for the graphical session) v
- | | printer.target
- v v
- <emphasis>default.target</emphasis> graphical-session.target</programlisting>
-
- </refsect1>
+ (various (various (various
+ timers...) paths...) sockets...) (sound devices)
+ | | | |
+ v v v v
+ timers.target paths.target sockets.target sound.target
+ | | |
+ \______________ _|_________________/ (bluetooth devices)
+ \ / |
+ V v
+ basic.target bluetooth.target
+ |
+ __________/ \_______ (smartcard devices)
+ / \ |
+ | | v
+ | v smartcard.target
+ v graphical-session-pre.target
+(various user services) | (printers)
+ | v |
+ | (services for the graphical session) v
+ | | printer.target
+ v v
+ <emphasis>default.target</emphasis> graphical-session.target</programlisting>
+
+ </refsect1>
<refsect1>
<title>Bootup in the Initial RAM Disk (initrd)</title>
<filename>/sysroot</filename>.
</para>
-<programlisting> : (beginning identical to above)
- :
- v
- basic.target
- | emergency.service
- ______________________/| |
- / | v
- | initrd-root-device.target <emphasis>emergency.target</emphasis>
- | |
- | v
- | sysroot.mount
- | |
- | v
- | initrd-root-fs.target
- | |
- | v
- v initrd-parse-etc.service
- (custom initrd |
- services...) v
- | (sysroot-usr.mount and
- | various mounts marked
- | with fstab option
- | x-initrd.mount...)
- | |
- | v
- | initrd-fs.target
- \______________________ |
- \|
- v
- initrd.target
- |
- v
- initrd-cleanup.service
- isolates to
- initrd-switch-root.target
- |
- v
- ______________________/|
- / v
- | initrd-udevadm-cleanup-db.service
- v |
- (custom initrd |
- services...) |
- \______________________ |
- \|
- v
- initrd-switch-root.target
- |
- v
- initrd-switch-root.service
- |
- v
- Transition to Host OS</programlisting>
+<programlisting> : (beginning identical to above)
+ :
+ v
+ basic.target
+ | emergency.service
+ ______________________/| |
+ / | v
+ | initrd-root-device.target <emphasis>emergency.target</emphasis>
+ | |
+ | v
+ | sysroot.mount
+ | |
+ | v
+ | initrd-root-fs.target
+ | |
+ | v
+ v initrd-parse-etc.service
+(custom initrd |
+ services...) v
+ | (sysroot-usr.mount and
+ | various mounts marked
+ | with fstab option
+ | x-initrd.mount...)
+ | |
+ | v
+ | initrd-fs.target
+ \______________________ |
+ \|
+ v
+ initrd.target
+ |
+ v
+ initrd-cleanup.service
+ isolates to
+ initrd-switch-root.target
+ |
+ v
+ ______________________/|
+ / v
+ | initrd-udevadm-cleanup-db.service
+ v |
+(custom initrd |
+ services...) |
+ \______________________ |
+ \|
+ v
+ initrd-switch-root.target
+ |
+ v
+ initrd-switch-root.service
+ |
+ v
+ Transition to Host OS</programlisting>
</refsect1>
<refsect1>
<para>System shutdown with systemd also consists of various target
units with some minimal ordering structure applied:</para>
-<programlisting> (conflicts with (conflicts with
- all system all file system
- services) mounts, swaps,
- | cryptsetup/
- | veritysetup
- | devices, ...)
- | |
- v v
- shutdown.target umount.target
- | |
- \_______ ______/
- \ /
- v
- (various low-level
- services)
- |
- v
- final.target
- |
- _____________________________________/ \_________________________________
- / | | \
- | | | |
- v v v v
-systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service
- | | | |
- v v v v
- <emphasis>reboot.target</emphasis> <emphasis>poweroff.target</emphasis> <emphasis>halt.target</emphasis> <emphasis>kexec.target</emphasis></programlisting>
+<programlisting> (conflicts with (conflicts with
+ all system all file system
+ services) mounts, swaps,
+ | cryptsetup/
+ | veritysetup
+ | devices, ...)
+ | |
+ v v
+ shutdown.target umount.target
+ | |
+ \_______ ______/
+ \ /
+ v
+ (various low-level
+ services)
+ |
+ v
+ final.target
+ |
+ ___________________________/ \_________________
+ / | | \
+ | | | |
+ v | | |
+systemd-reboot.service | | |
+ | v | |
+ | systemd-poweroff.service | |
+ v | v |
+ <emphasis>reboot.target</emphasis> | systemd-halt.service |
+ v | v
+ <emphasis>poweroff.target</emphasis> | systemd-kexec.service
+ v |
+ <emphasis>halt.target</emphasis> |
+ v
+ <emphasis>kexec.target</emphasis></programlisting>
<para>Commonly used system shutdown targets are <emphasis>emphasized</emphasis>.</para>
<term><option>keyfile-timeout=</option></term>
<listitem><para> Specifies the timeout for the device on
- which the key file resides and falls back to a password if
- it could not be mounted. See
+ which the key file resides or the device used as the key file,
+ and falls back to a password if it could not be accessed. See
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for key files on external devices.
</para></listitem>
interface org.freedesktop.oom1.Manager {
methods:
DumpByFileDescriptor(out h fd);
+ signals:
+ Killed(s cgroup,
+ s reason);
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
<variablelist class="dbus-method" generated="True" extra-ref="DumpByFileDescriptor()"/>
+ <variablelist class="dbus-signal" generated="True" extra-ref="Killed"/>
+
<!--End of Autogenerated section-->
<refsect2>
<title>Methods</title>
- <para>...</para>
+ <para><function>Killed</function> signal is sent when any cgroup is killed by oomd.</para>
+ <para>Note that more reasons will be added in the future, and the table below will be expanded accordingly.</para>
+ <table>
+ <title>Killing reasons</title>
+ <tgroup cols="2" align="left" colsep="1" rowsep="1">
+ <colspec colname="reason"/>
+ <colspec colname="description"/>
+ <thead>
+ <row>
+ <entry>Reason</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>memory-used</entry>
+ <entry>Application took too much memory and swap.</entry>
+ </row>
+ <row>
+ <entry>memory-pressure</entry>
+ <entry>Application took enough memory and swap to cause sufficient slowdown of other applications.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</refsect2>
</refsect1>
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t DefaultTimeoutAbortUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly t DefaultDeviceTimeoutUSec = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t DefaultRestartUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t DefaultStartLimitIntervalUSec = ...;
<!--property DefaultTimeoutAbortUSec is not documented!-->
+ <!--property DefaultDeviceTimeoutUSec is not documented!-->
+
<!--property DefaultRestartUSec is not documented!-->
<!--property DefaultStartLimitIntervalUSec is not documented!-->
<variablelist class="dbus-property" generated="True" extra-ref="DefaultTimeoutAbortUSec"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="DefaultDeviceTimeoutUSec"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="DefaultRestartUSec"/>
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartLimitIntervalUSec"/>
determines the fallback hostname.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ARCHITECTURE=</varname></term>
+ <listitem><para>A string that specifies which CPU architecture the userspace binaries require.
+ The architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
+ described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ The field is optional and should only be used when just single architecture is supported.
+ It may provide redundant information when used in a GPT partition with a GUID type that already
+ encodes the architecture. If this is not the case, the architecture should be specified in
+ e.g., an extension image, to prevent an incompatible host from loading it.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>SYSEXT_LEVEL=</varname></term>
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--unlock-key-file=</option><replaceable>PATH</replaceable></term>
+
+ <listitem><para>Use a file instead of a password/passphrase read from stdin to unlock the volume.
+ Expects the PATH to the file containing your key to unlock the volume. Currently there is nothing like
+ <option>--key-file-offset=</option> or <option>--key-file-size=</option> so this file has to only
+ contain the full key.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--pkcs11-token-uri=</option><replaceable>URI</replaceable></term>
<orderedlist>
<listitem><para>The <filename>repart.d/*.conf</filename> configuration files are loaded and parsed,
- and ordered by filename (without the directory prefix).</para></listitem>
+ and ordered by filename (without the directory prefix). For each configuration file,
+ drop-in files are looked for in directories with same name as the configuration file
+ with a suffix ".d" added.</para></listitem>
<listitem><para>The partition table already existing on the block device is loaded and
parsed.</para></listitem>
<listitem><para>Takes a file system path. If specified the <filename>*.conf</filename> files are read
from the specified directory instead of searching in <filename>/usr/lib/repart.d/*.conf</filename>,
<filename>/etc/repart.d/*.conf</filename>,
- <filename>/run/repart.d/*.conf</filename>.</para></listitem>
+ <filename>/run/repart.d/*.conf</filename>.</para>
+
+ <para>This parameter can be specified multiple times.</para></listitem>
</varlistentry>
<varlistentry>
accessed.</para>
<para>Note that there is no concept of enabling/disabling installed system extension images: all
- installed extension images are automatically activated at boot. However, you can place a symlink
- to <filename>/dev/null</filename> in <filename>/etc/extensions/</filename> to "mask" an image with
- the same name in a folder with lower precedence.</para>
+ installed extension images are automatically activated at boot. However, you can place an empty directory
+ named like the extension (no <filename>.raw</filename>) in <filename>/etc/extensions/</filename> to "mask"
+ an extension with the same name in a system folder with lower precedence.</para>
<para>A simple mechanism for version compatibility is enforced: a system extension image must carry a
<filename>/usr/lib/extension-release.d/extension-release.<replaceable>$name</replaceable></filename>
file, which must match its image name, that is compared with the host <filename>os-release</filename>
- file: the contained <varname>ID=</varname> fields have to match, as well as the
- <varname>SYSEXT_LEVEL=</varname> field (if defined). If the latter is not defined, the
- <varname>VERSION_ID=</varname> field has to match instead. System extensions should not ship a
- <filename>/usr/lib/os-release</filename> file (as that would be merged into the host
- <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable). The
- <filename>extension-release</filename> file follows the same format and semantics, and carries the same
+ file: the contained <varname>ID=</varname> fields have to match unless <literal>_any</literal> is set
+ for the extension. If the extension <varname>ID=</varname> is not <literal>_any</literal>, the
+ <varname>SYSEXT_LEVEL=</varname> field (if defined) has to match. If the latter is not defined, the
+ <varname>VERSION_ID=</varname> field has to match instead. If the extension defines the
+ <varname>ARCHITECTURE=</varname> field and the value is not <literal>_any</literal> it has to match the kernel's
+ architecture reported by <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ but the used architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
+ described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ System extensions should not ship a <filename>/usr/lib/os-release</filename> file (as that would be merged
+ into the host <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable).
+ The <filename>extension-release</filename> file follows the same format and semantics, and carries the same
content, as the <filename>os-release</filename> file of the OS, but it describes the resources carried
in the extension image.</para>
</refsect1>
100ms.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>DefaultDeviceTimeoutSec=</varname></term>
+
+ <listitem><para>Configures the default timeout for waiting for devices. It can be changed per
+ device via the <varname>x-systemd.device-timeout=</varname> option in <filename>/etc/fstab</filename>
+ and <filename>/etc/crypttab</filename> (see
+ <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+ Defaults to 90s.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>DefaultStartLimitIntervalSec=</varname></term>
<term><varname>DefaultStartLimitBurst=</varname></term>
<variablelist>
<varlistentry>
<term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></varname></term>
+ <term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></varname></term>
<listitem><para>This name is set based on the numeric ordering information given by the firmware
- for on-board devices. The name consists of the prefix, letter <constant>o</constant>, and a number
- specified by the firmware. This is only available for PCI devices.</para>
+ for on-board devices. Different schemes are used depending on the firmware type, as described in the table below.</para>
+
+ <table>
+ <title>Onboard naming schemes</title>
+
+ <tgroup cols='2'>
+ <thead>
+ <row>
+ <entry>Format</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></entry>
+ <entry>PCI onboard index</entry>
+ </row>
+
+ <row>
+ <entry><replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></entry>
+ <entry>Devicetree alias index</entry>
+ </row>
+
+ </tbody>
+ </tgroup>
+ </table>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>v252</constant></term>
+
+ <listitem><para>Added naming scheme for platform devices with devicetree aliases.</para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
<filename>/dev/net/tun</filename> device.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>KeepCarrier=</varname></term>
+ <listitem>
+ <para>Takes a boolean. If enabled, to make the interface maintain its carrier status, the file
+ descriptor of the interface is kept open. This may be useful to keep the interface in running
+ state, for example while the backing process is temporarily shutdown. Defaults to
+ <literal>no</literal>.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<term><varname>StartupCPUWeight=<replaceable>weight</replaceable></varname></term>
<listitem>
- <para>Assign the specified CPU time weight to the processes executed, if the unified control group
- hierarchy is used on the system. These options take an integer value and control the
- <literal>cpu.weight</literal> control group attribute. The allowed range is 1 to 10000. Defaults to
- 100. For details about this control group attribute, see <ulink
- url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>
- and <ulink url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS
- Scheduler</ulink>. The available CPU time is split up among all units within one slice relative to
- their CPU time weight. A higher weight means more CPU time, a lower weight means less.</para>
+ <para>These options accept an integer value or a the special string "idle":</para>
+ <itemizedlist>
+ <listitem>
+ <para>If set to an integer value, assign the specified CPU time weight to the processes executed,
+ if the unified control group hierarchy is used on the system. These options control the
+ <literal>cpu.weight</literal> control group attribute. The allowed range is 1 to 10000. Defaults to
+ 100. For details about this control group attribute, see <ulink
+ url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>
+ and <ulink url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS
+ Scheduler</ulink>. The available CPU time is split up among all units within one slice relative to
+ their CPU time weight. A higher weight means more CPU time, a lower weight means less.</para>
+ </listitem>
+ <listitem>
+ <para>If set to the special string "idle", mark the cgroup for "idle scheduling", which means
+ that it will get CPU resources only when there are no processes not marked in this way to execute in this
+ cgroup or its siblings. This setting corresponds to the <literal>cpu.idle</literal> cgroup attribute.</para>
+
+ <para>Note that this value only has an effect on cgroup-v2, for cgroup-v1 it is equivalent to the minimum weight.</para>
+ </listitem>
+ </itemizedlist>
<para>While <varname>StartupCPUWeight=</varname> applies to the startup and shutdown phases of the system,
<varname>CPUWeight=</varname> applies to normal runtime of the system, and if the former is not set also to
c_args = get_option('c_args')
# Our json library does not support -ffinite-math-only, which is enabled by -Ofast or -ffast-math.
-if (('-Ofast' in c_args or '-ffast-math' in c_args or '-ffinite-math-only' in c_args) and not ('-fno-finite-math-only' in c_args))
+if (('-Ofast' in c_args or '-ffast-math' in c_args or '-ffinite-math-only' in c_args) and '-fno-finite-math-only' not in c_args)
error('-Ofast, -ffast-math, or -ffinite-math-only is specified in c_args.')
endif
install : true,
install_dir : systemgeneratordir)
+meson.add_install_script(meson_make_symlink,
+ systemgeneratordir / 'systemd-fstab-generator',
+ rootlibexecdir / 'systemd-sysroot-fstab-check')
+
if want_tests != 'false'
test('test-fstab-generator',
test_fstab_generator_sh,
HostonlyInitrd=yes
# Prevent ASAN warnings when building the image
Environment=ASAN_OPTIONS=verify_asan_link_order=false
+OutputDirectory=mkosi.output
[Content]
BuildDirectory=mkosi.builddir
Cache=mkosi.cache
-InstallDirectory=mkosi.installdir
SourceFileTransferFinal=copy-git-others
[Host]
#
# Gabor Kelemen <kelemeng at gnome dot hu>, 2015, 2016.
# Balázs Úr <urbalazs at gmail dot com>, 2016.
+# Balázs Meskó <meskobalazs@mailbox.org>, 2022.
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-08 17:48+0100\n"
-"PO-Revision-Date: 2016-08-23 18:03+0100\n"
-"Last-Translator: Balázs Úr <urbalazs@gmail.com>\n"
-"Language-Team: Hungarian <openscope at googlegroups dot com>\n"
+"PO-Revision-Date: 2022-08-09 20:19+0000\n"
+"Last-Translator: Balázs Meskó <meskobalazs@mailbox.org>\n"
+"Language-Team: Hungarian <https://translate.fedoraproject.org/projects/"
+"systemd/master/hu/>\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Lokalize 2.0\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.13\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
#: src/home/org.freedesktop.home1.policy:13
msgid "Create a home area"
-msgstr ""
+msgstr "Saját terület létrehozása"
#: src/home/org.freedesktop.home1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
msgid "Authentication is required to create a user's home area."
-msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+msgstr "Hitelesítés szükséges a felhasználó saját területének létrehozásához."
#: src/home/org.freedesktop.home1.policy:23
msgid "Remove a home area"
-msgstr ""
+msgstr "Saját terület eltávolítása"
#: src/home/org.freedesktop.home1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
msgid "Authentication is required to remove a user's home area."
-msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+msgstr "Hitelesítés szükséges a felhasználó saját területének eltávolításához."
#: src/home/org.freedesktop.home1.policy:33
msgid "Check credentials of a home area"
-msgstr ""
+msgstr "Saját terület hitelesítő adatainak ellenőrzése"
#: src/home/org.freedesktop.home1.policy:34
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
msgid ""
"Authentication is required to check credentials against a user's home area."
msgstr ""
-"Hitelesítés szükséges az aktív munkamenetek, felhasználók és munkaállomások "
-"kezeléséhez."
+"Hitelesítés szükséges a hitelesítő adatok a felhasználó saját területével "
+"való összevetéséhez."
#: src/home/org.freedesktop.home1.policy:43
msgid "Update a home area"
-msgstr ""
+msgstr "Saját terület frissítése"
#: src/home/org.freedesktop.home1.policy:44
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
msgid "Authentication is required to update a user's home area."
-msgstr ""
-"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy "
-"munkaállomáshoz"
+msgstr "Hitelesítés szükséges a felhasználó saját területének frissítéséhez."
#: src/home/org.freedesktop.home1.policy:53
msgid "Resize a home area"
-msgstr ""
+msgstr "Saját terület átméretezése"
#: src/home/org.freedesktop.home1.policy:54
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to resize a user's home area."
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a felhasználó saját területének átméretezéséhez."
#: src/home/org.freedesktop.home1.policy:63
msgid "Change password of a home area"
-msgstr ""
+msgstr "Saját terület hitelesítő adatainak módosítása"
#: src/home/org.freedesktop.home1.policy:64
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
msgid ""
"Authentication is required to change the password of a user's home area."
msgstr ""
-"Hitelesítés szükséges az aktív munkamenetek, felhasználók és munkaállomások "
-"kezeléséhez."
+"Hitelesítés szükséges a felhasználó saját területének jelszavának "
+"módosításához."
#: src/hostname/org.freedesktop.hostname1.policy:20
msgid "Set hostname"
#: src/hostname/org.freedesktop.hostname1.policy:42
msgid "Authentication is required to set local machine information."
-msgstr "Hitelesítés szükséges a helyi gép információinak beállításához."
+msgstr "Hitelesítés szükséges a helyi gépinformációk beállításához."
#: src/hostname/org.freedesktop.hostname1.policy:51
msgid "Get product UUID"
-msgstr ""
+msgstr "Termék UUID-jának lekérése"
#: src/hostname/org.freedesktop.hostname1.policy:52
-#, fuzzy
-#| msgid "Authentication is required to reload '$(unit)'."
msgid "Authentication is required to get product UUID."
-msgstr "Hitelesítés szükséges a következő újratöltéséhez: „$(unit)”."
+msgstr "Hitelesítés szükséges a termék UUID-jának lekéréséhez."
#: src/import/org.freedesktop.import1.policy:22
msgid "Import a VM or container image"
-msgstr "VM vagy konténer lemezkép importálása"
+msgstr "VM vagy konténer lemezképének importálása"
#: src/import/org.freedesktop.import1.policy:23
msgid "Authentication is required to import a VM or container image"
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép importálásához."
+msgstr "Hitelesítés szükséges a VM vagy konténer lemezképének importálásához"
#: src/import/org.freedesktop.import1.policy:32
msgid "Export a VM or container image"
-msgstr "VM vagy konténer lemezkép exportálása"
+msgstr "VM vagy konténer lemezképének exportálása"
#: src/import/org.freedesktop.import1.policy:33
msgid "Authentication is required to export a VM or container image"
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép exportálásához."
+msgstr "Hitelesítés szükséges a VM vagy konténer lemezképének exportálásához"
#: src/import/org.freedesktop.import1.policy:42
msgid "Download a VM or container image"
-msgstr "VM vagy konténer lemezkép letöltése"
+msgstr "VM vagy konténer lemezképének letöltése"
#: src/import/org.freedesktop.import1.policy:43
msgid "Authentication is required to download a VM or container image"
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép letöltéséhez."
+msgstr "Hitelesítés szükséges a VM vagy konténer lemezképének letöltéséhez"
#: src/locale/org.freedesktop.locale1.policy:22
msgid "Set system locale"
-msgstr "Területi beállítás megadása"
+msgstr "Rendszer területi beállításának megadása"
#: src/locale/org.freedesktop.locale1.policy:23
msgid "Authentication is required to set the system locale."
#: src/locale/org.freedesktop.locale1.policy:33
msgid "Set system keyboard settings"
-msgstr "Rendszer billentyűzetbeállítások megadása"
+msgstr "Rendszer billentyűzetbeállításainak megadása"
#: src/locale/org.freedesktop.locale1.policy:34
msgid "Authentication is required to set the system keyboard settings."
#: src/login/org.freedesktop.login1.policy:22
msgid "Allow applications to inhibit system shutdown"
-msgstr "Alkalmazások meggátolhatják a rendszer leállítását"
+msgstr "Az alkalmazások meggátolhatják a rendszer leállítását"
#: src/login/org.freedesktop.login1.policy:23
msgid ""
#: src/login/org.freedesktop.login1.policy:33
msgid "Allow applications to delay system shutdown"
-msgstr "Alkalmazások késleltethetik a rendszer leállítását"
+msgstr "Az alkalmazások késleltethetik a rendszer leállítását"
#: src/login/org.freedesktop.login1.policy:34
msgid "Authentication is required for an application to delay system shutdown."
#: src/login/org.freedesktop.login1.policy:44
msgid "Allow applications to inhibit system sleep"
-msgstr "Alkalmazások meggátolhatják a rendszer altatását"
+msgstr "Az alkalmazások meggátolhatják a rendszer altatását"
#: src/login/org.freedesktop.login1.policy:45
msgid "Authentication is required for an application to inhibit system sleep."
#: src/login/org.freedesktop.login1.policy:55
msgid "Allow applications to delay system sleep"
-msgstr "Alkalmazások késleltethetik a rendszer altatását"
+msgstr "Az alkalmazások késleltethetik a rendszer altatását"
#: src/login/org.freedesktop.login1.policy:56
msgid "Authentication is required for an application to delay system sleep."
#: src/login/org.freedesktop.login1.policy:65
msgid "Allow applications to inhibit automatic system suspend"
-msgstr "Alkalmazások meggátolhatják a rendszer automatikus felfüggesztését"
+msgstr "Az alkalmazások meggátolhatják a rendszer automatikus felfüggesztését"
#: src/login/org.freedesktop.login1.policy:66
msgid ""
#: src/login/org.freedesktop.login1.policy:75
msgid "Allow applications to inhibit system handling of the power key"
msgstr ""
-"Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését"
#: src/login/org.freedesktop.login1.policy:76
msgid ""
#: src/login/org.freedesktop.login1.policy:86
msgid "Allow applications to inhibit system handling of the suspend key"
msgstr ""
-"Alkalmazások meggátolhatják a felfüggesztés gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják a felfüggesztés gomb rendszer általi kezelését"
#: src/login/org.freedesktop.login1.policy:87
msgid ""
#: src/login/org.freedesktop.login1.policy:97
msgid "Allow applications to inhibit system handling of the hibernate key"
msgstr ""
-"Alkalmazások meggátolhatják a hibernálás gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják a hibernálás gomb rendszer általi kezelését"
#: src/login/org.freedesktop.login1.policy:98
msgid ""
#: src/login/org.freedesktop.login1.policy:107
msgid "Allow applications to inhibit system handling of the lid switch"
-msgstr "Alkalmazások meggátolhatják a fedélkapcsoló rendszer általi kezelését"
+msgstr ""
+"Az alkalmazások meggátolhatják a fedélkapcsoló rendszer általi kezelését"
#: src/login/org.freedesktop.login1.policy:108
msgid ""
"kezelésének meggátlásához."
#: src/login/org.freedesktop.login1.policy:117
-#, fuzzy
-#| msgid "Allow applications to inhibit system handling of the power key"
msgid "Allow applications to inhibit system handling of the reboot key"
msgstr ""
-"Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják az újraindítás gomb rendszer általi kezelését"
#: src/login/org.freedesktop.login1.policy:118
-#, fuzzy
-#| msgid ""
-#| "Authentication is required for an application to inhibit system handling "
-#| "of the power key."
msgid ""
"Authentication is required for an application to inhibit system handling of "
"the reboot key."
msgstr ""
-"Hitelesítés szükséges egy alkalmazás számára a bekapcsoló gomb rendszer "
+"Hitelesítés szükséges egy alkalmazás számára az újraindítás gomb rendszer "
"általi kezelésének meggátlásához."
#: src/login/org.freedesktop.login1.policy:128
#: src/login/org.freedesktop.login1.policy:129
msgid "Explicit request is required to run programs as a non-logged-in user."
msgstr ""
-"Határozott kérés szükséges a programfuttatáshoz be nem jelentkezett "
-"felhasználóként."
+"Határozott kérés szükséges a be nem jelentkezett felhasználókénti "
+"programfuttatáshoz."
#: src/login/org.freedesktop.login1.policy:138
msgid "Allow non-logged-in users to run programs"
#: src/login/org.freedesktop.login1.policy:139
msgid "Authentication is required to run programs as a non-logged-in user."
msgstr ""
-"Hitelesítés szükséges a programfuttatáshoz be nem jelentkezett "
-"felhasználóként."
+"Hitelesítés szükséges a be nem jelentkezett felhasználókénti "
+"programfuttatáshoz."
#: src/login/org.freedesktop.login1.policy:148
msgid "Allow attaching devices to seats"
-msgstr "Eszközök csatolásának engedélyezése munkaállomásokhoz"
+msgstr "Eszközök munkaállomásokhoz csatolásának engedélyezése"
#: src/login/org.freedesktop.login1.policy:149
msgid "Authentication is required to attach a device to a seat."
msgstr ""
-"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy "
-"munkaállomáshoz"
+"Hitelesítés szükséges az eszköz munkaállomáshoz csatolásának "
+"engedélyezéséhez."
#: src/login/org.freedesktop.login1.policy:159
msgid "Flush device to seat attachments"
#: src/login/org.freedesktop.login1.policy:213
msgid "Reboot the system while other users are logged in"
-msgstr "A rendszer újraindítása mialatt be vannak jelentkezve más felhasználók"
+msgstr "A rendszer újraindítása miközben be vannak jelentkezve más felhasználók"
#: src/login/org.freedesktop.login1.policy:214
msgid ""
"ennek meggátlását kérte."
#: src/login/org.freedesktop.login1.policy:235
-#, fuzzy
-#| msgid "Hibernate the system"
msgid "Halt the system"
-msgstr "A rendszer hibernálása"
+msgstr "A rendszer leállítása"
#: src/login/org.freedesktop.login1.policy:236
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
msgid "Authentication is required to halt the system."
-msgstr "Hitelesítés szükséges a rendszer hibernálásához."
+msgstr "Hitelesítés szükséges a rendszer leállításához."
#: src/login/org.freedesktop.login1.policy:246
-#, fuzzy
-#| msgid "Hibernate the system while other users are logged in"
msgid "Halt the system while other users are logged in"
-msgstr "A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók"
+msgstr "A rendszer leállítása miközben más felhasználók be vannak jelentkezve"
#: src/login/org.freedesktop.login1.policy:247
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while other users are "
-#| "logged in."
msgid ""
"Authentication is required to halt the system while other users are logged "
"in."
msgstr ""
-"Hitelesítés szükséges a rendszer hibernálásához miközben be vannak "
-"jelentkezve más felhasználók."
+"Hitelesítés szükséges a rendszer leállításához miközben más felhasználók be "
+"vannak jelentkezve."
#: src/login/org.freedesktop.login1.policy:257
-#, fuzzy
-#| msgid "Hibernate the system while an application is inhibiting this"
msgid "Halt the system while an application is inhibiting this"
-msgstr "A rendszer hibernálása miközben egy alkalmazás ennek meggátlását kérte"
+msgstr "A rendszer leállítása miközben egy alkalmazás ennek meggátlását kérte"
#: src/login/org.freedesktop.login1.policy:258
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while an application "
-#| "is inhibiting this."
msgid ""
"Authentication is required to halt the system while an application is "
"inhibiting this."
msgstr ""
-"Hitelesítés szükséges a rendszer hibernálásához miközben egy alkalmazás "
-"ennek meggátlását kérte."
+"Hitelesítés szükséges a rendszer leállításához miközben egy alkalmazás ennek "
+"meggátlását kérte."
#: src/login/org.freedesktop.login1.policy:268
msgid "Suspend the system"
#: src/login/org.freedesktop.login1.policy:310
msgid "Hibernate the system while other users are logged in"
-msgstr "A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók"
+msgstr "A rendszer hibernálása miközben be vannak jelentkezve más felhasználók"
#: src/login/org.freedesktop.login1.policy:311
msgid ""
#: src/login/org.freedesktop.login1.policy:352
msgid "Set the reboot \"reason\" in the kernel"
-msgstr ""
+msgstr "Az újraindítás „okának” beállítása a kernelben"
#: src/login/org.freedesktop.login1.policy:353
-#, fuzzy
-#| msgid "Authentication is required to set the system timezone."
msgid "Authentication is required to set the reboot \"reason\" in the kernel."
-msgstr "Hitelesítés szükséges a rendszer időzónájának beállításához."
+msgstr ""
+"Hitelesítés szükséges a rendszer újraindítási „okának” beállításához a "
+"kernelben."
#: src/login/org.freedesktop.login1.policy:363
-#, fuzzy
-#| msgid "Allow indication to the firmware to boot to setup interface"
msgid "Indicate to the firmware to boot to setup interface"
-msgstr "A firmware-nek jelezhető, hogy a beállítófelületet bootolja"
+msgstr ""
+"Jelzés a firmware számára, hogy a beállítófelületet indítsa el "
+"rendszerindításkor"
#: src/login/org.freedesktop.login1.policy:364
msgid ""
"Authentication is required to indicate to the firmware to boot to setup "
"interface."
msgstr ""
-"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet "
-"bootolja"
+"Hitelesítés szükséges, hogy a firmware a beállítófelületet indítsa el "
+"rendszerindításkor."
#: src/login/org.freedesktop.login1.policy:374
msgid "Indicate to the boot loader to boot to the boot loader menu"
msgstr ""
+"Jelzés a rendszerbetöltő számára, hogy a rendszerbetöltő menüt indítsa el "
+"rendszerindításkor"
#: src/login/org.freedesktop.login1.policy:375
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to indicate to the firmware to boot to setup "
-#| "interface."
msgid ""
"Authentication is required to indicate to the boot loader to boot to the "
"boot loader menu."
msgstr ""
-"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet "
-"bootolja"
+"Hitelesítés szükséges, hogy a firmware a rendszerbetöltő menüt indítsa el "
+"rendszerindításkor."
#: src/login/org.freedesktop.login1.policy:385
msgid "Indicate to the boot loader to boot a specific entry"
msgstr ""
+"Jelzés a rendszerbetöltő számára, hogy egy adott bejegyzést indítson el "
+"rendszerindításkor"
#: src/login/org.freedesktop.login1.policy:386
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to indicate to the firmware to boot to setup "
-#| "interface."
msgid ""
"Authentication is required to indicate to the boot loader to boot into a "
"specific boot loader entry."
msgstr ""
-"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet "
-"bootolja"
+"Hitelesítés szükséges, hogy a rendszerbetöltő egy adott bejegyzést indítson "
+"el rendszerindításkor."
#: src/login/org.freedesktop.login1.policy:396
msgid "Set a wall message"
#: src/login/org.freedesktop.login1.policy:406
msgid "Change Session"
-msgstr ""
+msgstr "Munkamenet módosítása"
#: src/login/org.freedesktop.login1.policy:407
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
msgid "Authentication is required to change the virtual terminal."
-msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
+msgstr "Hitelesítés szükséges a virtuális terminál módosításához."
#: src/machine/org.freedesktop.machine1.policy:22
msgid "Log into a local container"
#: src/machine/org.freedesktop.machine1.policy:23
msgid "Authentication is required to log into a local container."
-msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe."
+msgstr "Hitelesítés szükséges a helyi konténerbe történő bejelentkezéshez."
#: src/machine/org.freedesktop.machine1.policy:32
msgid "Log into the local host"
#: src/machine/org.freedesktop.machine1.policy:33
msgid "Authentication is required to log into the local host."
-msgstr "Hitelesítés szükséges a bejelentkezéshez a helyi gépre."
+msgstr "Hitelesítés szükséges a helyi gépre történtő bejelentkezéshez."
#: src/machine/org.freedesktop.machine1.policy:42
msgid "Acquire a shell in a local container"
#: src/machine/org.freedesktop.machine1.policy:95
msgid "Manage local virtual machine and container images"
-msgstr "Helyi virtuális gép és konténer lemezképek kezelése"
+msgstr "Helyi virtuális gépek és konténerek lemezképeinek kezelése"
#: src/machine/org.freedesktop.machine1.policy:96
msgid ""
"Authentication is required to manage local virtual machine and container "
"images."
msgstr ""
-"Hitelesítés szükséges a helyi virtuális gép és konténer lemezképek "
+"Hitelesítés szükséges a helyi virtuális gépek és konténerek lemezképeinek "
"kezeléséhez."
#: src/network/org.freedesktop.network1.policy:22
msgid "Set NTP servers"
-msgstr ""
+msgstr "NTP-kiszolgálók beállítása"
#: src/network/org.freedesktop.network1.policy:23
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to set NTP servers."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges az NTP-kiszolgálók beállításához."
#: src/network/org.freedesktop.network1.policy:33
#: src/resolve/org.freedesktop.resolve1.policy:44
msgid "Set DNS servers"
-msgstr ""
+msgstr "DNS-kiszolgálók beállítása"
#: src/network/org.freedesktop.network1.policy:34
#: src/resolve/org.freedesktop.resolve1.policy:45
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to set DNS servers."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges a DNS-kiszolgálók beállításához."
#: src/network/org.freedesktop.network1.policy:44
#: src/resolve/org.freedesktop.resolve1.policy:55
msgid "Set domains"
-msgstr ""
+msgstr "Domainek beállítása"
#: src/network/org.freedesktop.network1.policy:45
#: src/resolve/org.freedesktop.resolve1.policy:56
-#, fuzzy
-#| msgid "Authentication is required to stop '$(unit)'."
msgid "Authentication is required to set domains."
-msgstr "Hitelesítés szükséges a következő leállításához: „$(unit)”."
+msgstr "Hitelesítés szükséges a domainek beállításához."
#: src/network/org.freedesktop.network1.policy:55
#: src/resolve/org.freedesktop.resolve1.policy:66
msgid "Set default route"
-msgstr ""
+msgstr "Alapértelmezett hálózati útvonal beállítása"
#: src/network/org.freedesktop.network1.policy:56
#: src/resolve/org.freedesktop.resolve1.policy:67
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
msgid "Authentication is required to set default route."
-msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
+msgstr ""
+"Hitelesítés szükséges az alapértelmezett hálózati útvonal beállításához."
#: src/network/org.freedesktop.network1.policy:66
#: src/resolve/org.freedesktop.resolve1.policy:77
msgid "Enable/disable LLMNR"
-msgstr ""
+msgstr "LLMNR engedélyezése/letiltása"
#: src/network/org.freedesktop.network1.policy:67
#: src/resolve/org.freedesktop.resolve1.policy:78
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
msgid "Authentication is required to enable or disable LLMNR."
-msgstr "Hitelesítés szükséges a rendszer hibernálásához."
+msgstr "Hitelesítés szükséges az LLMNR engedélyezéséhez vagy kikapcsolásához."
#: src/network/org.freedesktop.network1.policy:77
#: src/resolve/org.freedesktop.resolve1.policy:88
msgid "Enable/disable multicast DNS"
-msgstr ""
+msgstr "Multicast DNS engedélyezése/letiltása"
#: src/network/org.freedesktop.network1.policy:78
#: src/resolve/org.freedesktop.resolve1.policy:89
-#, fuzzy
-#| msgid "Authentication is required to log into the local host."
msgid "Authentication is required to enable or disable multicast DNS."
-msgstr "Hitelesítés szükséges a bejelentkezéshez a helyi gépre."
+msgstr ""
+"Hitelesítés szükséges a multicast DNS engedélyezéséhez vagy kikapcsolásához."
#: src/network/org.freedesktop.network1.policy:88
#: src/resolve/org.freedesktop.resolve1.policy:99
msgid "Enable/disable DNS over TLS"
-msgstr ""
+msgstr "TLS feletti DNS engedélyezése/letiltása"
#: src/network/org.freedesktop.network1.policy:89
#: src/resolve/org.freedesktop.resolve1.policy:100
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
msgid "Authentication is required to enable or disable DNS over TLS."
-msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
+msgstr ""
+"Hitelesítés szükséges a TLS feletti DNS engedélyezéséhez vagy "
+"kikapcsolásához."
#: src/network/org.freedesktop.network1.policy:99
#: src/resolve/org.freedesktop.resolve1.policy:110
msgid "Enable/disable DNSSEC"
-msgstr ""
+msgstr "DNSSEC engedélyezése/letiltása"
#: src/network/org.freedesktop.network1.policy:100
#: src/resolve/org.freedesktop.resolve1.policy:111
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
msgid "Authentication is required to enable or disable DNSSEC."
-msgstr "Hitelesítés szükséges a rendszer hibernálásához."
+msgstr "Hitelesítés szükséges a DNSSEC engedélyezéséhez vagy kikapcsolásához."
#: src/network/org.freedesktop.network1.policy:110
#: src/resolve/org.freedesktop.resolve1.policy:121
msgid "Set DNSSEC Negative Trust Anchors"
-msgstr ""
+msgstr "DNSSEC Negative Trust Anchor beállítása"
#: src/network/org.freedesktop.network1.policy:111
#: src/resolve/org.freedesktop.resolve1.policy:122
-#, fuzzy
-#| msgid "Authentication is required to set the system locale."
msgid "Authentication is required to set DNSSEC Negative Trust Anchors."
-msgstr "Hitelesítés szükséges a rendszer területi beállításainak megadásához."
+msgstr "Hitelestés szükséges a DNSSEC Negative Trust Anchor beállításához."
#: src/network/org.freedesktop.network1.policy:121
msgid "Revert NTP settings"
-msgstr ""
+msgstr "NTP-beállítások visszaállítása"
#: src/network/org.freedesktop.network1.policy:122
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to reset NTP settings."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges az NTP-beállítások visszaállításához."
#: src/network/org.freedesktop.network1.policy:132
msgid "Revert DNS settings"
-msgstr ""
+msgstr "DNS-beállítások visszaállítása"
#: src/network/org.freedesktop.network1.policy:133
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to reset DNS settings."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges a DNS-beállítások visszaállításához."
#: src/network/org.freedesktop.network1.policy:143
msgid "DHCP server sends force renew message"
-msgstr ""
+msgstr "A DHCP-kiszolgáló kényszerített megújítási üzenetet küld"
#: src/network/org.freedesktop.network1.policy:144
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to send force renew message."
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a kényszerített megújítási üzenetet küldéséhez."
#: src/network/org.freedesktop.network1.policy:154
msgid "Renew dynamic addresses"
-msgstr ""
+msgstr "Dinamikus címke megújítása"
#: src/network/org.freedesktop.network1.policy:155
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to renew dynamic addresses."
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a dinamikus címke megújításához."
#: src/network/org.freedesktop.network1.policy:165
msgid "Reload network settings"
-msgstr ""
+msgstr "Hálózati beállítások újratöltése"
#: src/network/org.freedesktop.network1.policy:166
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
msgid "Authentication is required to reload network settings."
-msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+msgstr "Hitelesítés szükséges a hálózati beállítások újratöltéséhez."
#: src/network/org.freedesktop.network1.policy:176
msgid "Reconfigure network interface"
-msgstr ""
+msgstr "Hálózati csatoló újrakonfigurálása"
#: src/network/org.freedesktop.network1.policy:177
-#, fuzzy
-#| msgid "Authentication is required to reboot the system."
msgid "Authentication is required to reconfigure network interface."
-msgstr "Hitelesítés szükséges a rendszer újraindításához."
+msgstr "Hitelesítés szükséges a hálózati csatoló újrakonfigurálásához."
#: src/portable/org.freedesktop.portable1.policy:13
msgid "Inspect a portable service image"
-msgstr ""
+msgstr "Hordozható szolgáltatás lemezképének vizsgálata"
#: src/portable/org.freedesktop.portable1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to import a VM or container image"
msgid "Authentication is required to inspect a portable service image."
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép importálásához."
+msgstr ""
+"Hitelesítés szükséges a hordozható szolgáltatás lemezképének vizsgálatához."
#: src/portable/org.freedesktop.portable1.policy:23
msgid "Attach or detach a portable service image"
-msgstr ""
+msgstr "Hordozható szolgáltatás lemezképének csatolása vagy leválasztása"
#: src/portable/org.freedesktop.portable1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
msgid ""
"Authentication is required to attach or detach a portable service image."
msgstr ""
-"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy "
-"munkaállomáshoz"
+"Hitelesítés szükséges a hordozható szolgáltatás lemezképének csatolásához "
+"vagy leválasztásához."
#: src/portable/org.freedesktop.portable1.policy:34
msgid "Delete or modify portable service image"
-msgstr ""
+msgstr "Hordozható szolgáltatás lemezképének törlése vagy módosítása"
#: src/portable/org.freedesktop.portable1.policy:35
-#, fuzzy
-#| msgid "Authentication is required to download a VM or container image"
msgid ""
"Authentication is required to delete or modify a portable service image."
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép letöltéséhez."
+msgstr ""
+"Hitelesítés szükséges a hordozható szolgáltatás lemezképének törléséhez vagy "
+"módosításához."
#: src/resolve/org.freedesktop.resolve1.policy:22
msgid "Register a DNS-SD service"
-msgstr ""
+msgstr "DNS-SD szolgáltatás regisztrálása"
#: src/resolve/org.freedesktop.resolve1.policy:23
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to register a DNS-SD service"
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a DNS-SD szolgáltatás regisztrálásához"
#: src/resolve/org.freedesktop.resolve1.policy:33
msgid "Unregister a DNS-SD service"
-msgstr ""
+msgstr "DNS-SD szolgáltatás kiregisztrálása"
#: src/resolve/org.freedesktop.resolve1.policy:34
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
msgid "Authentication is required to unregister a DNS-SD service"
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a DNS-SD szolgáltatás kiregisztrálásához"
#: src/resolve/org.freedesktop.resolve1.policy:132
msgid "Revert name resolution settings"
-msgstr ""
+msgstr "Névfeloldási beállítások visszaállítása"
#: src/resolve/org.freedesktop.resolve1.policy:133
-#, fuzzy
-#| msgid "Authentication is required to set the system keyboard settings."
msgid "Authentication is required to reset name resolution settings."
-msgstr ""
-"Hitelesítés szükséges a rendszer billentyűzetbeállításainak megadásához."
+msgstr "Hitelesítés szükséges a névfeloldási beállítások visszaállításához."
#: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time"
msgstr "Hitelesítés szükséges a következő újraindításához: „$(unit)”."
#: src/core/dbus-unit.c:535
-#, fuzzy
-#| msgid "Authentication is required to set properties on '$(unit)'."
msgid ""
"Authentication is required to send a UNIX signal to the processes of "
"'$(unit)'."
msgstr ""
-"Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”."
+"Hitelesítés szükséges a UNIX szignál elküldéséhez a következő folyamatai "
+"számára: „$(unit)”."
#: src/core/dbus-unit.c:566
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
"Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”."
#: src/core/dbus-unit.c:708
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgid ""
"Authentication is required to delete files and directories associated with "
"'$(unit)'."
msgstr ""
-"Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: "
-"„$(unit)”."
+"Hitelesítés szükséges a következővel kapcsolatos fájlok és könyvtárak "
+"törléséhez: „$(unit)”."
#: src/core/dbus-unit.c:757
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgid ""
"Authentication is required to freeze or thaw the processes of '$(unit)' unit."
msgstr ""
-"Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: "
+"Hitelesítés szükséges a következő egység folyamatainak befagyasztásához: "
"„$(unit)”."
#~ msgid "Authentication is required to kill '$(unit)'."
ACTION=="remove", GOTO="sensor_end"
+# device matching the sensor's label, name and the machine's DMI data for IIO devices
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="usb|i2c|platform", ATTR{label}!="", \
+ IMPORT{builtin}="hwdb 'sensor:$attr{label}:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
+ GOTO="sensor_end"
+
+# Before Linux v6.0, cros-ec-accel used a non-standard 'location' sysfs file
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="platform", \
+ ATTR{name}=="cros-ec-accel|cros-ec-accel-legacy", ATTR{location}=="base", \
+ IMPORT{builtin}="hwdb 'sensor:accel-base:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
+ GOTO="sensor_end"
+
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="platform", \
+ ATTR{name}=="cros-ec-accel|cros-ec-accel-legacy", ATTR{location}=="lid", \
+ IMPORT{builtin}="hwdb 'sensor:accel-display:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
+ GOTO="sensor_end"
+
# device matching the sensor's name and the machine's DMI data for IIO devices
SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="usb|i2c|platform", \
IMPORT{builtin}="hwdb 'sensor:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
# Protocol analyzers
ENV{ID_SIGNAL_ANALYZER}=="?*", ENV{DEVTYPE}=="usb_device", TAG+="uaccess"
+ENV{ID_SIGNAL_ANALYZER}=="?*", KERNEL=="ttyACM[0-9]*", TAG+="uaccess"
# rfkill / radio killswitches
KERNEL=="rfkill", SUBSYSTEM=="misc", TAG+="uaccess"
fi
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
+ if [ -d /sys/fs/cgroup/systemd/ ]; then
+ COMPREPLY+=( $(cd /sys/fs/cgroup/systemd/ && compgen -o nospace -o dirnames "$cur") )
+ elif [ -d /sys/fs/cgroup/ ]; then
+ COMPREPLY+=( $(cd /sys/fs/cgroup/ && compgen -o nospace -o dirnames "$cur") )
+ fi
}
complete -F _systemd_cgtop systemd-cgtop
#include "terminal-util.h"
#include "util.h"
+#define PCI_CLASS_GRAPHICS_CARD 0x30000
+
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
return 0;
}
+static int has_multiple_graphics_cards(void) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
+ bool found = false;
+ int r;
+
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_subsystem(e, "pci", /* match = */ true);
+ if (r < 0)
+ return r;
+
+ /* class is an unsigned number, let's validate the value later. */
+ r = sd_device_enumerator_add_match_sysattr(e, "class", NULL, /* match = */ true);
+ if (r < 0)
+ return r;
+
+ FOREACH_DEVICE(e, dev) {
+ const char *s;
+ unsigned long c;
+
+ if (sd_device_get_sysattr_value(dev, "class", &s) < 0)
+ continue;
+
+ if (safe_atolu(s, &c) < 0)
+ continue;
+
+ if (c != PCI_CLASS_GRAPHICS_CARD)
+ continue;
+
+ if (found)
+ return true; /* This is the second device. */
+
+ found = true; /* Found the first device. */
+ }
+
+ return false;
+}
+
static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) {
const char *subsystem, *sysname, *value;
sd_device *parent;
return -ENODATA;
c += strspn(c, DIGITS);
- if (*c == '-' && !STARTSWITH_SET(c, "-LVDS-", "-Embedded DisplayPort-"))
+ if (*c == '-' && !STARTSWITH_SET(c, "-LVDS-", "-Embedded DisplayPort-", "-eDP-"))
/* A connector DRM device, let's ignore all but LVDS and eDP! */
return -EOPNOTSUPP;
value, subsystem, sysname);
/* Graphics card */
- if (class == 0x30000) {
+ if (class == PCI_CLASS_GRAPHICS_CARD) {
*ret = parent;
return 0;
}
static int validate_device(sd_device *device) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerate = NULL;
- const char *v, *subsystem;
+ const char *v, *sysname, *subsystem;
sd_device *parent, *other;
int r;
* device to userspace. However, we still need to make sure that we use "raw" only if no
* "firmware" or "platform" device for the same device exists. */
+ r = sd_device_get_sysname(device, &sysname);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "Failed to get sysname: %m");
+
r = sd_device_get_subsystem(device, &subsystem);
if (r < 0)
- return r;
+ return log_device_debug_errno(device, r, "Failed to get subsystem: %m");
if (!streq(subsystem, "backlight"))
return true;
r = sd_device_get_sysattr_value(device, "type", &v);
if (r < 0)
- return r;
+ return log_device_debug_errno(device, r, "Failed to read 'type' sysattr: %m");
if (!streq(v, "raw"))
return true;
r = find_pci_or_platform_parent(device, &parent);
if (r < 0)
- return r;
+ return log_device_debug_errno(device, r, "Failed to find PCI or platform parent: %m");
r = sd_device_get_subsystem(parent, &subsystem);
if (r < 0)
- return r;
+ return log_device_debug_errno(parent, r, "Failed to get subsystem: %m");
+
+ if (DEBUG_LOGGING) {
+ const char *s = NULL;
+
+ (void) sd_device_get_syspath(parent, &s);
+ log_device_debug(device, "Found %s parent device: %s", subsystem, strna(s));
+ }
r = sd_device_enumerator_new(&enumerate);
if (r < 0)
- return r;
+ return log_oom_debug();
r = sd_device_enumerator_allow_uninitialized(enumerate);
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to allow uninitialized devices: %m");
- r = sd_device_enumerator_add_match_subsystem(enumerate, "backlight", true);
+ r = sd_device_enumerator_add_match_subsystem(enumerate, "backlight", /* match = */ true);
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to add subsystem match: %m");
+
+ r = sd_device_enumerator_add_nomatch_sysname(enumerate, sysname);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add sysname unmatch: %m");
+
+ r = sd_device_enumerator_add_match_sysattr(enumerate, "type", "platform", /* match = */ true);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add sysattr match: %m");
+
+ r = sd_device_enumerator_add_match_sysattr(enumerate, "type", "firmware", /* match = */ true);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add sysattr match: %m");
+
+ if (streq(subsystem, "pci")) {
+ r = has_multiple_graphics_cards();
+ if (r < 0)
+ return log_debug_errno(r, "Failed to check if the system has multiple graphics cards: %m");
+ if (r > 0) {
+ /* If the system has multiple graphics cards, then we cannot associate platform
+ * devices on non-PCI bus (especially WMI bus) with PCI devices. Let's ignore all
+ * backlight devices that do not have the same parent PCI device. */
+ log_debug("Found multiple graphics cards on PCI bus. "
+ "Skipping to associate platform backlight devices on non-PCI bus.");
+
+ r = sd_device_enumerator_add_match_parent(enumerate, parent);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add parent match: %m");
+ }
+ }
FOREACH_DEVICE(enumerate, other) {
const char *other_subsystem;
sd_device *other_parent;
- if (same_device(device, other) > 0)
- continue;
-
- if (sd_device_get_sysattr_value(other, "type", &v) < 0 ||
- !STR_IN_SET(v, "platform", "firmware"))
- continue;
-
/* OK, so there's another backlight device, and it's a platform or firmware device.
* Let's see if we can verify it belongs to the same device as ours. */
- if (find_pci_or_platform_parent(other, &other_parent) < 0)
+ r = find_pci_or_platform_parent(other, &other_parent);
+ if (r < 0) {
+ log_device_debug_errno(other, r, "Failed to get PCI or platform parent, ignoring: %m");
continue;
+ }
if (same_device(parent, other_parent) > 0) {
- const char *device_sysname = NULL, *other_sysname = NULL;
-
/* Both have the same PCI parent, that means we are out. */
-
- (void) sd_device_get_sysname(device, &device_sysname);
- (void) sd_device_get_sysname(other, &other_sysname);
-
- log_debug("Skipping backlight device %s, since device %s is on same PCI device and takes precedence.",
- device_sysname, other_sysname);
+ if (DEBUG_LOGGING) {
+ const char *other_sysname = NULL, *other_type = NULL;
+
+ (void) sd_device_get_sysname(other, &other_sysname);
+ (void) sd_device_get_sysattr_value(other, "type", &other_type);
+ log_device_debug(device,
+ "Found another %s backlight device %s on the same PCI, skipping.",
+ strna(other_type), strna(other_sysname));
+ }
return false;
}
- if (sd_device_get_subsystem(other_parent, &other_subsystem) < 0)
+ r = sd_device_get_subsystem(other_parent, &other_subsystem);
+ if (r < 0) {
+ log_device_debug_errno(other_parent, r, "Failed to get subsystem, ignoring: %m");
continue;
+ }
if (streq(other_subsystem, "platform") && streq(subsystem, "pci")) {
- const char *device_sysname = NULL, *other_sysname = NULL;
-
/* The other is connected to the platform bus and we are a PCI device, that also means we are out. */
-
- (void) sd_device_get_sysname(device, &device_sysname);
- (void) sd_device_get_sysname(other, &other_sysname);
-
- log_debug("Skipping backlight device %s, since device %s is a platform device and takes precedence.",
- device_sysname, other_sysname);
+ if (DEBUG_LOGGING) {
+ const char *other_sysname = NULL, *other_type = NULL;
+
+ (void) sd_device_get_sysname(other, &other_sysname);
+ (void) sd_device_get_sysattr_value(other, "type", &other_type);
+ log_device_debug(device,
+ "Found another %s backlight device %s, which has higher precedence, skipping.",
+ strna(other_type), strna(other_sysname));
+ }
return false;
}
}
/* Special values for all weight knobs on unified hierarchy */
#define CGROUP_WEIGHT_INVALID UINT64_MAX
+#define CGROUP_WEIGHT_IDLE UINT64_C(0)
#define CGROUP_WEIGHT_MIN UINT64_C(1)
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
#define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC)
+/* We use an extra-long timeout for the reload. This is because a reload or reexec means generators are rerun
+ * which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can
+ * have their timeout, and for everything else there's the same time budget in place. */
+#define DAEMON_RELOAD_TIMEOUT_SEC (DEFAULT_TIMEOUT_USEC * 2)
+
#define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC)
#define DEFAULT_START_LIMIT_BURST 5
return buffer;
}
+struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length) {
+ assert(addr);
+ assert(length <= HW_ADDR_MAX_SIZE);
+
+ addr->length = length;
+ memcpy_safe(addr->bytes, bytes, length);
+ return addr;
+}
+
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) {
int r;
#define HW_ADDR_NULL ((const struct hw_addr_data){})
+struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length);
+
void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state);
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b);
static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) {
return ret;
}
-int touch(const char *path) {
- return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
-}
-
int symlink_idempotent(const char *from, const char *to, bool make_relative) {
_cleanup_free_ char *relpath = NULL;
int r;
#include "alloc-util.h"
#include "errno-util.h"
#include "time-util.h"
+#include "user-util.h"
#define MODE_INVALID ((mode_t) -1)
RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
-int touch(const char *path);
+
+static inline int touch(const char *path) {
+ return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
+}
int symlink_idempotent(const char *from, const char *to, bool make_relative);
#include "hash-funcs.h"
#include "path-util.h"
+#include "strv.h"
void string_hash_func(const char *p, struct siphash *state) {
siphash24_compress(p, strlen(p) + 1, state);
DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
char, string_hash_func, string_compare_func, free,
void, free);
+DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free,
+ char, string_hash_func, string_compare_func, free,
+ char*, strv_free);
void path_hash_func(const char *q, struct siphash *state) {
bool add_slash = false;
extern const struct hash_ops string_hash_ops;
extern const struct hash_ops string_hash_ops_free;
extern const struct hash_ops string_hash_ops_free_free;
+extern const struct hash_ops string_hash_ops_free_strv_free;
void path_hash_func(const char *p, struct siphash *state);
extern const struct hash_ops path_hash_ops;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
+#include <fnmatch.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "extract-word.h"
#include "fd-util.h"
#include "fs-util.h"
+#include "glob-util.h"
#include "log.h"
#include "macro.h"
#include "path-util.h"
return false;
}
+
+int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
+ assert(pattern);
+ assert(prefix);
+
+ for (const char *a = pattern, *b = prefix;;) {
+ _cleanup_free_ char *g = NULL, *h = NULL;
+ const char *p, *q;
+ int r, s;
+
+ r = path_find_first_component(&a, /* accept_dot_dot = */ false, &p);
+ if (r < 0)
+ return r;
+
+ s = path_find_first_component(&b, /* accept_dot_dot = */ false, &q);
+ if (s < 0)
+ return s;
+
+ if (s == 0) {
+ /* The pattern matches the prefix. */
+ if (ret) {
+ char *t;
+
+ t = path_join(prefix, p);
+ if (!t)
+ return -ENOMEM;
+
+ *ret = t;
+ }
+ return true;
+ }
+
+ if (r == 0)
+ break;
+
+ if (r == s && strneq(p, q, r))
+ continue; /* common component. Check next. */
+
+ g = strndup(p, r);
+ if (!g)
+ return -ENOMEM;
+
+ if (!string_is_glob(g))
+ break;
+
+ /* We found a glob component. Check if the glob pattern matches the prefix component. */
+
+ h = strndup(q, s);
+ if (!h)
+ return -ENOMEM;
+
+ if (fnmatch(g, h, 0) != 0)
+ break;
+ }
+
+ /* The pattern does not match the prefix. */
+ if (ret)
+ *ret = NULL;
+ return false;
+}
bool path_strv_contains(char **l, const char *path);
bool prefixed_path_strv_contains(char **l, const char *path);
+
+int path_glob_can_match(const char *pattern, const char *prefix, char **ret);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#if defined(__i386__) || defined(__x86_64__)
-#include <cpuid.h>
-#endif
-
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include "sha256.h"
#include "time-util.h"
-/* This is a "best effort" kind of thing, but has no real security value.
- * So, this should only be used by random_bytes(), which is not meant for
- * crypto. This could be made better, but we're *not* trying to roll a
- * userspace prng here, or even have forward secrecy, but rather just do
- * the shortest thing that is at least better than libc rand(). */
+/* This is a "best effort" kind of thing, but has no real security value. So, this should only be used by
+ * random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a
+ * userspace prng here, or even have forward secrecy, but rather just do the shortest thing that is at least
+ * better than libc rand(). */
static void fallback_random_bytes(void *p, size_t n) {
static thread_local uint64_t fallback_counter = 0;
struct {
.stamp_mono = now(CLOCK_MONOTONIC),
.stamp_real = now(CLOCK_REALTIME),
.pid = getpid(),
- .tid = gettid()
+ .tid = gettid(),
};
#if HAVE_SYS_AUXV_H
#include "verbs.h"
#include "virt.h"
+/* EFI_BOOT_OPTION_DESCRIPTION_MAX sets the maximum length for the boot option description
+ * stored in NVRAM. The UEFI spec does not specify a minimum or maximum length for this
+ * string, but we limit the length to something reasonable to prevent from the firmware
+ * having to deal with a potentially too long string. */
+#define EFI_BOOT_OPTION_DESCRIPTION_MAX ((size_t) 255)
+
static char *arg_esp_path = NULL;
static char *arg_xbootldr_path = NULL;
static bool arg_print_esp_path = false;
ARG_INSTALL_SOURCE_HOST,
ARG_INSTALL_SOURCE_AUTO,
} arg_install_source = ARG_INSTALL_SOURCE_AUTO;
+static char *arg_efi_boot_option_description = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep);
static const char *arg_dollar_boot_path(void) {
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
return arg_xbootldr_path ?: arg_esp_path;
}
+static const char *pick_efi_boot_option_description(void) {
+ return arg_efi_boot_option_description ?: "Linux Boot Manager";
+}
+
static int acquire_esp(
bool unprivileged_mode,
bool graceful,
break;
}
- if (isempty(arg_entry_token) || !string_is_safe(arg_entry_token))
+ if (isempty(arg_entry_token) || !(utf8_is_valid(arg_entry_token) && string_is_safe(arg_entry_token)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token);
log_debug("Using entry token: %s", arg_entry_token);
"Failed to determine current boot order: %m");
if (first || r == 0) {
- r = efi_add_boot_option(slot, "Linux Boot Manager",
+ r = efi_add_boot_option(slot, pick_efi_boot_option_description(),
part, pstart, psize,
uuid, path);
if (r < 0)
return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
- log_info("Created EFI boot entry \"Linux Boot Manager\".");
+ log_info("Created EFI boot entry \"%s\".", pick_efi_boot_option_description());
}
return insert_into_order(slot, first);
" Generate JSON output\n"
" --all-architectures\n"
" Install all supported EFI architectures\n"
+ " --efi-boot-option-description=DESCRIPTION\n"
+ " Description of the entry in the boot option list\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
ARG_ENTRY_TOKEN,
ARG_JSON,
ARG_ARCH_ALL,
+ ARG_EFI_BOOT_OPTION_DESCRIPTION,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "esp-path", required_argument, NULL, ARG_ESP_PATH },
- { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
- { "boot-path", required_argument, NULL, ARG_BOOT_PATH },
- { "root", required_argument, NULL, ARG_ROOT },
- { "image", required_argument, NULL, ARG_IMAGE },
- { "install-source", required_argument, NULL, ARG_INSTALL_SOURCE },
- { "print-esp-path", no_argument, NULL, 'p' },
- { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
- { "print-boot-path", no_argument, NULL, 'x' },
- { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "graceful", no_argument, NULL, ARG_GRACEFUL },
- { "quiet", no_argument, NULL, 'q' },
- { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
- { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */
- { "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
- { "json", required_argument, NULL, ARG_JSON },
- { "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "esp-path", required_argument, NULL, ARG_ESP_PATH },
+ { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
+ { "boot-path", required_argument, NULL, ARG_BOOT_PATH },
+ { "root", required_argument, NULL, ARG_ROOT },
+ { "image", required_argument, NULL, ARG_IMAGE },
+ { "install-source", required_argument, NULL, ARG_INSTALL_SOURCE },
+ { "print-esp-path", no_argument, NULL, 'p' },
+ { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
+ { "print-boot-path", no_argument, NULL, 'x' },
+ { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "graceful", no_argument, NULL, ARG_GRACEFUL },
+ { "quiet", no_argument, NULL, 'q' },
+ { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
+ { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */
+ { "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
+ { "json", required_argument, NULL, ARG_JSON },
+ { "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
+ { "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION },
{}
};
arg_arch_all = true;
break;
+ case ARG_EFI_BOOT_OPTION_DESCRIPTION:
+ if (isempty(optarg) || !(string_is_safe(optarg) && utf8_is_valid(optarg))) {
+ _cleanup_free_ char *escaped = NULL;
+
+ escaped = cescape(optarg);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Invalid --efi-boot-option-description=: %s", strna(escaped));
+ }
+ if (strlen(optarg) > EFI_BOOT_OPTION_DESCRIPTION_MAX)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--efi-boot-option-description= too long: %zu > %zu", strlen(optarg), EFI_BOOT_OPTION_DESCRIPTION_MAX);
+ r = free_and_strdup_warn(&arg_efi_boot_option_description, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case '?':
return -EINVAL;
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
- if (have_bootloader_esp_uuid && !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
- printf("WARNING: The boot loader reports a different ESP UUID than detected!\n");
+ if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
+ !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
+ printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
+ SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
+ SD_ID128_FORMAT_VAL(esp_uuid));
if (stub) {
printf(" Stub: %s\n", stub);
config_add_entry(config, entry);
if (config->secure_boot_enroll == ENROLL_FORCE && strcaseeq16(dirent->FileName, u"auto"))
- /* if we auto enroll sucessfully this call does not return, if it fails we still
+ /* if we auto enroll successfully this call does not return, if it fails we still
* want to add other potential entries to the menu */
secure_boot_enroll_at(root_dir, entry->path);
}
*/
/* allocate SizeOfImage + SectionAlignment because the new_buffer can move up to Alignment-1 bytes */
kernel.num = EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment);
- err = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel.num, &kernel.addr);
+ err = BS->AllocatePages(AllocateAnyPages, EfiLoaderCode, kernel.num, &kernel.addr);
if (err != EFI_SUCCESS)
return EFI_OUT_OF_RESOURCES;
new_buffer = PHYSICAL_ADDRESS_TO_POINTER(ALIGN_TO(kernel.addr, kernel_alignment));
efi_crt0,
]
-possible_link_flags = [
- '-Wl,--no-warn-execstack',
- '-Wl,--no-warn-rwx-segments',
-]
-efi_ldflags += cc.get_supported_link_arguments(possible_link_flags)
+foreach arg : ['-Wl,--no-warn-execstack',
+ '-Wl,--no-warn-rwx-segments']
+ # We need to check the correct linker for supported args. This is what
+ # cc.has_multi_link_arguments() is for, but it helpfully overrides our
+ # choice of linker by putting its own -fuse-ld= arg after ours.
+ if run_command('bash', '-c',
+ 'exec "$@" -x c -o/dev/null <(echo "int main(void){return 0;}")' +
+ ' -fuse-ld=' + efi_ld + ' -Wl,--fatal-warnings ' + arg,
+ 'bash', cc.cmd_array(),
+ check : false).returncode() == 0
+ efi_ldflags += arg
+ endif
+endforeach
if efi_arch[1] in ['aarch64', 'arm', 'riscv64']
efi_ldflags += ['-shared']
}
/* if we are not in secure boot mode, or none was provided, accept a custom command line and replace
- * the built-in one. We also do a superficial check whether first chararacter of passed command line
+ * the built-in one. We also do a superficial check whether first character of passed command line
* is printable character (for compat with some Dell systems which fill in garbage?). */
if ((!secure_boot_enabled() || cmdline_len == 0) &&
loaded_image->LoadOptionsSize > 0 &&
#include "bpf-socket-bind.h"
#include "btrfs-util.h"
#include "bus-error.h"
+#include "bus-locator.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "cgroup.h"
static void cgroup_apply_unified_cpu_weight(Unit *u, uint64_t weight) {
char buf[DECIMAL_STR_MAX(uint64_t) + 2];
+ if (weight == CGROUP_WEIGHT_IDLE)
+ return;
xsprintf(buf, "%" PRIu64 "\n", weight);
(void) set_attribute_and_warn(u, "cpu", "cpu.weight", buf);
}
+static void cgroup_apply_unified_cpu_idle(Unit *u, uint64_t weight) {
+ int r;
+ bool is_idle;
+ const char *idle_val;
+
+ is_idle = weight == CGROUP_WEIGHT_IDLE;
+ idle_val = one_zero(is_idle);
+ r = cg_set_attribute("cpu", u->cgroup_path, "cpu.idle", idle_val);
+ if (r < 0 && (r != -ENOENT || is_idle))
+ log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%s': %m",
+ "cpu.idle", empty_to_root(u->cgroup_path), idle_val);
+}
+
static void cgroup_apply_unified_cpu_quota(Unit *u, usec_t quota, usec_t period) {
char buf[(DECIMAL_STR_MAX(usec_t) + 1) * 2 + 1];
}
static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) {
+ /* we don't support idle in cgroupv1 */
+ if (weight == CGROUP_WEIGHT_IDLE)
+ return CGROUP_CPU_SHARES_MIN;
+
return CLAMP(weight * CGROUP_CPU_SHARES_DEFAULT / CGROUP_WEIGHT_DEFAULT,
CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX);
}
} else
weight = CGROUP_WEIGHT_DEFAULT;
+ cgroup_apply_unified_cpu_idle(u, weight);
cgroup_apply_unified_cpu_weight(u, weight);
cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);
pp = strjoina("/", pp, suffix_path);
path_simplify(pp);
- r = sd_bus_call_method(u->manager->system_bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "AttachProcessesToUnit",
- &error, NULL,
- "ssau",
- NULL /* empty unit name means client's unit, i.e. us */, pp, 1, (uint32_t) pid);
+ r = bus_call_method(u->manager->system_bus,
+ bus_systemd_mgr,
+ "AttachProcessesToUnit",
+ &error, NULL,
+ "ssau",
+ NULL /* empty unit name means client's unit, i.e. us */, pp, 1, (uint32_t) pid);
if (r < 0)
return log_unit_debug_errno(u, r, "Failed to attach unit process " PID_FMT " via the bus: %s", pid, bus_error_message(&error, r));
}
DISABLE_WARNING_TYPE_LIMITS;
-BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
REENABLE_WARNING;
+static int bus_cgroup_set_cpu_weight(
+ Unit *u,
+ const char *name,
+ uint64_t *p,
+ sd_bus_message *message,
+ UnitWriteFlags flags,
+ sd_bus_error *error) {
+ uint64_t v;
+ int r;
+ assert(p);
+ r = sd_bus_message_read(message, "t", &v);
+ if (r < 0)
+ return r;
+ if (!CGROUP_WEIGHT_IS_OK(v) && v != CGROUP_WEIGHT_IDLE)
+ return sd_bus_error_setf(
+ error, SD_BUS_ERROR_INVALID_ARGS, "Value specified in %s is out of range", name);
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ *p = v;
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
+ if (v == CGROUP_WEIGHT_INVALID)
+ unit_write_settingf(u, flags, name, "%s=", name);
+ else if (v == CGROUP_WEIGHT_IDLE)
+ unit_write_settingf(u, flags, name, "%s=idle", name);
+ else
+ unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, v);
+ }
+ return 1;
+}
+
static int bus_cgroup_set_tasks_max(
Unit *u,
const char *name,
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutAbortUSec", "t", property_get_default_timeout_abort_usec, 0, 0),
+ SD_BUS_PROPERTY("DefaultDeviceTimeoutUSec", "t", bus_property_get_usec, offsetof(Manager, default_device_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
/* The following two items are obsolete alias */
if (r < 0)
return r;
- if (!UNIT_VTABLE(u)->bus_set_property)
- return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
- "Objects of this type do not support setting properties.");
-
r = sd_bus_message_enter_container(message, 'v', NULL);
if (r < 0)
return r;
/* If not for real, then mask out the two target flags */
f = for_real ? flags : (flags & ~(UNIT_RUNTIME|UNIT_PERSISTENT));
- r = UNIT_VTABLE(u)->bus_set_property(u, name, message, f, error);
+ if (UNIT_VTABLE(u)->bus_set_property)
+ r = UNIT_VTABLE(u)->bus_set_property(u, name, message, f, error);
+ else
+ r = 0;
if (r == 0 && u->transient && u->load_state == UNIT_STUB)
r = bus_unit_set_transient_property(u, name, message, f, error);
if (r == 0)
* indefinitely for plugged in devices, something which cannot
* happen for the other units since their operations time out
* anyway. */
- u->job_running_timeout = u->manager->default_timeout_start_usec;
+ u->job_running_timeout = u->manager->default_device_timeout_usec;
u->ignore_on_isolate = true;
if (d->state != DEVICE_DEAD)
/* So here's a special hack, to compensate for the fact that the udev database's reload cycles are not
* synchronized with our own reload cycles: when we detect that the SYSTEMD_WANTS property of a device
- * changes while the device unit is already up, let's manually trigger any new units listed in it not
- * seen before. This typically happens during the boot-time switch root transition, as udev devices
- * will generally already be up in the initrd, but SYSTEMD_WANTS properties get then added through udev
- * rules only available on the host system, and thus only when the initial udev coldplug trigger runs.
+ * changes while the device unit is already up, let's skip to trigger units that were already listed
+ * and are active, and start units otherwise. This typically happens during the boot-time switch root
+ * transition, as udev devices will generally already be up in the initrd, but SYSTEMD_WANTS properties
+ * get then added through udev rules only available on the host system, and thus only when the initial
+ * udev coldplug trigger runs.
*
* We do this only if the device has been up already when we parse this, as otherwise the usual
* dependency logic that is run from the dead → plugged transition will trigger these deps. */
STRV_FOREACH(i, added) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
- continue;
+ if (strv_contains(d->wants_property, *i)) {
+ Unit *v;
+
+ v = manager_get_unit(u->manager, *i);
+ if (v && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(v)))
+ continue; /* The unit was already listed and is running. */
+ }
r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
if (r < 0)
/* qemu_fw_cfg would be loaded by udev later, but we want to import credentials from it super early */
{ "qemu_fw_cfg", "/sys/firmware/qemu_fw_cfg", false, false, in_qemu },
+
+ /* dmi-sysfs is needed to import credentials from it super early */
+ { "dmi-sysfs", "/sys/firmware/dmi/entries", false, false, NULL },
};
_cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
unsigned i;
{{type}}.AllowedMemoryNodes, config_parse_allowed_cpuset, 0, offsetof({{type}}, cgroup_context.cpuset_mems)
{{type}}.StartupAllowedMemoryNodes, config_parse_allowed_cpuset, 0, offsetof({{type}}, cgroup_context.startup_cpuset_mems)
{{type}}.CPUAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpu_accounting)
-{{type}}.CPUWeight, config_parse_cg_weight, 0, offsetof({{type}}, cgroup_context.cpu_weight)
-{{type}}.StartupCPUWeight, config_parse_cg_weight, 0, offsetof({{type}}, cgroup_context.startup_cpu_weight)
+{{type}}.CPUWeight, config_parse_cg_cpu_weight, 0, offsetof({{type}}, cgroup_context.cpu_weight)
+{{type}}.StartupCPUWeight, config_parse_cg_cpu_weight, 0, offsetof({{type}}, cgroup_context.startup_cpu_weight)
{{type}}.CPUShares, config_parse_cpu_shares, 0, offsetof({{type}}, cgroup_context.cpu_shares)
{{type}}.StartupCPUShares, config_parse_cpu_shares, 0, offsetof({{type}}, cgroup_context.startup_cpu_shares)
{{type}}.CPUQuota, config_parse_cpu_quota, 0, offsetof({{type}}, cgroup_context)
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
+DEFINE_CONFIG_PARSE_PTR(config_parse_cg_cpu_weight, cg_cpu_weight_parse, uint64_t, "Invalid CPU weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
{ config_parse_restrict_filesystems, "FILESYSTEMS" },
{ config_parse_cpu_shares, "SHARES" },
{ config_parse_cg_weight, "WEIGHT" },
+ { config_parse_cg_cpu_weight, "CPUWEIGHT" },
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },
CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice);
CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight);
+CONFIG_PARSER_PROTOTYPE(config_parse_cg_cpu_weight);
CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
static usec_t arg_default_timeout_start_usec;
static usec_t arg_default_timeout_stop_usec;
static usec_t arg_default_timeout_abort_usec;
+static usec_t arg_default_device_timeout_usec;
static bool arg_default_timeout_abort_set;
static usec_t arg_default_start_limit_interval;
static unsigned arg_default_start_limit_burst;
{ "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
{ "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
{ "Manager", "DefaultTimeoutAbortSec", config_parse_default_timeout_abort, 0, NULL },
+ { "Manager", "DefaultDeviceTimeoutSec", config_parse_sec, 0, &arg_default_device_timeout_usec },
{ "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */
{ "Manager", "DefaultStartLimitIntervalSec", config_parse_sec, 0, &arg_default_start_limit_interval },
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
NULL,
+ NULL,
NULL);
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we use
m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
m->default_timeout_abort_usec = arg_default_timeout_abort_usec;
m->default_timeout_abort_set = arg_default_timeout_abort_set;
+ m->default_device_timeout_usec = arg_default_device_timeout_usec;
m->default_restart_usec = arg_default_restart_usec;
m->default_start_limit_interval = arg_default_start_limit_interval;
m->default_start_limit_burst = arg_default_start_limit_burst;
arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC;
arg_default_timeout_abort_set = false;
+ arg_default_device_timeout_usec = DEFAULT_TIMEOUT_USEC;
arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
arg_runtime_watchdog = 0;
.default_timeout_start_usec = DEFAULT_TIMEOUT_USEC,
.default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC,
.default_restart_usec = DEFAULT_RESTART_USEC,
+ .default_device_timeout_usec = DEFAULT_TIMEOUT_USEC,
.original_log_level = -1,
.original_log_target = _LOG_TARGET_INVALID,
ExecOutput default_std_output, default_std_error;
usec_t default_restart_usec, default_timeout_start_usec, default_timeout_stop_usec;
+ usec_t default_device_timeout_usec;
usec_t default_timeout_abort_usec;
bool default_timeout_abort_set;
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
- r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755" TMPFS_LIMITS_DEV);
+ r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755" TMPFS_LIMITS_PRIVATE_DEV);
if (r < 0)
goto fail;
(void) unit_reset_accounting(u);
/* We check only for User= option to keep behavior consistent with logic for service units,
- * i.e. having 'Delegate=true Group=foo' w/o specifing User= has no effect. */
+ * i.e. having 'Delegate=true Group=foo' w/o specifying User= has no effect. */
if (s->user && unit_cgroup_delegate(u))
return scope_enter_start_chown(s);
unit_prune_cgroup(u);
}
+static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
+ Scope *s = SCOPE(u);
+
+ if (managed_oom)
+ log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
+ else
+ log_unit_debug(u, "Process of control group was killed by the OOM killer.");
+
+ /* This will probably need to be modified when scope units get an oom-policy */
+ switch (s->state) {
+
+ case SCOPE_START_CHOWN:
+ case SCOPE_RUNNING:
+ case SCOPE_STOP_SIGTERM:
+ scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_OOM_KILL);
+ break;
+
+ case SCOPE_STOP_SIGKILL:
+ if (s->result == SCOPE_SUCCESS)
+ s->result = SCOPE_FAILURE_OOM_KILL;
+ break;
+ /* SCOPE_DEAD, SCOPE_ABANDONED, and SCOPE_FAILED end up in default */
+ default:
+ ;
+ }
+}
+
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
Scope *s = SCOPE(u);
[SCOPE_SUCCESS] = "success",
[SCOPE_FAILURE_RESOURCES] = "resources",
[SCOPE_FAILURE_TIMEOUT] = "timeout",
+ [SCOPE_FAILURE_OOM_KILL] = "oom-kill",
};
DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
.reset_failed = scope_reset_failed,
.notify_cgroup_empty = scope_notify_cgroup_empty_event,
+ .notify_cgroup_oom = scope_notify_cgroup_oom_event,
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
SCOPE_SUCCESS,
SCOPE_FAILURE_RESOURCES,
SCOPE_FAILURE_TIMEOUT,
+ SCOPE_FAILURE_OOM_KILL,
_SCOPE_RESULT_MAX,
_SCOPE_RESULT_INVALID = -EINVAL,
} ScopeResult;
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
#DefaultTimeoutAbortSec=
+#DefaultDeviceTimeoutSec=90s
#DefaultRestartSec=100ms
#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
if (v->base == TIMER_CALENDAR) {
usec_t b, rebased;
- /* If we know the last time this was
- * triggered, schedule the job based relative
- * to that. If we don't, just start from
- * the activation time. */
-
- if (t->last_trigger.realtime > 0)
+ /* Update last_trigger to 'now' in case the system time changes, so that
+ * next_elapse is not stuck with a future date. */
+ if (time_change)
+ b = ts.realtime;
+ /* If we know the last time this was triggered, schedule the job based relative
+ * to that. If we don't, just start from the activation time. */
+ else if (t->last_trigger.realtime > 0)
b = t->last_trigger.realtime;
- else {
- if (state_translation_table[t->state] == UNIT_ACTIVE)
- b = UNIT(t)->inactive_exit_timestamp.realtime;
- else
- b = ts.realtime;
- }
+ else if (state_translation_table[t->state] == UNIT_ACTIVE)
+ b = UNIT(t)->inactive_exit_timestamp.realtime;
+ else
+ b = ts.realtime;
r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
if (r < 0)
unit_add_to_gc_queue(other);
+ /* The unit 'other' may not be wanted by the unit 'u'. */
+ unit_submit_to_stop_when_unneeded_queue(other);
+
done = false;
break;
}
arg_tpm2_device = streq(optarg, "auto") ? NULL : optarg;
break;
- case ARG_TPM2_PCRS:
+ case ARG_TPM2_PCRS: {
+ uint32_t mask;
+
if (isempty(optarg)) {
arg_tpm2_pcr_mask = 0;
break;
}
- uint32_t mask;
r = tpm2_parse_pcrs(optarg, &mask);
if (r < 0)
return r;
arg_tpm2_pcr_mask |= mask;
break;
+ }
case ARG_NAME:
if (isempty(optarg)) {
#include "cryptsetup-util.h"
#include "env-util.h"
#include "escape.h"
+#include "fileio.h"
#include "libfido2-util.h"
#include "main-func.h"
#include "memory-util.h"
#include "tpm2-util.h"
static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID;
+static char *arg_unlock_keyfile = NULL;
static char *arg_pkcs11_token_uri = NULL;
static char *arg_fido2_device = NULL;
static char *arg_tpm2_device = NULL;
assert_cc(sizeof(arg_wipe_slots_mask) * 8 >= _ENROLL_TYPE_MAX);
+STATIC_DESTRUCTOR_REGISTER(arg_unlock_keyfile, freep);
STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep);
STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_node, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_wipe_slots, freep);
static bool wipe_requested(void) {
return arg_n_wipe_slots > 0 ||
" --version Show package version\n"
" --password Enroll a user-supplied password\n"
" --recovery-key Enroll a recovery key\n"
+ " --unlock-key-file=PATH\n"
+ " Use a file to unlock the volume\n"
" --pkcs11-token-uri=URI\n"
" Specify PKCS#11 security token URI\n"
" --fido2-credential-algorithm=STRING\n"
ARG_VERSION = 0x100,
ARG_PASSWORD,
ARG_RECOVERY_KEY,
+ ARG_UNLOCK_KEYFILE,
ARG_PKCS11_TOKEN_URI,
ARG_FIDO2_DEVICE,
ARG_TPM2_DEVICE,
{ "version", no_argument, NULL, ARG_VERSION },
{ "password", no_argument, NULL, ARG_PASSWORD },
{ "recovery-key", no_argument, NULL, ARG_RECOVERY_KEY },
+ { "unlock-key-file", required_argument, NULL, ARG_UNLOCK_KEYFILE },
{ "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI },
{ "fido2-credential-algorithm", required_argument, NULL, ARG_FIDO2_CRED_ALG },
{ "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE },
arg_enroll_type = ENROLL_RECOVERY;
break;
+ case ARG_UNLOCK_KEYFILE:
+ r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_unlock_keyfile);
+ if (r < 0)
+ return r;
+ break;
+
case ARG_PKCS11_TOKEN_URI: {
_cleanup_free_ char *uri = NULL;
break;
}
- case ARG_TPM2_PIN: {
+ case ARG_TPM2_PIN:
r = parse_boolean_argument("--tpm2-with-pin=", optarg, &arg_tpm2_pin);
if (r < 0)
return r;
break;
- }
case ARG_WIPE_SLOT: {
const char *p = optarg;
if (!vk)
return log_oom();
+ if (arg_unlock_keyfile) {
+ _cleanup_(erase_and_freep) char *password = NULL;
+ size_t password_len;
+
+ r = read_full_file_full(
+ AT_FDCWD,
+ arg_unlock_keyfile,
+ 0,
+ SIZE_MAX,
+ READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+ NULL,
+ &password,
+ &password_len);
+ if (r < 0)
+ return log_error_errno(r, "Reading keyfile %s failed: %m", arg_unlock_keyfile);
+
+ r = crypt_volume_key_get(
+ cd,
+ CRYPT_ANY_SLOT,
+ vk,
+ &vks,
+ password,
+ password_len);
+ if (r < 0)
+ return log_error_errno(r, "Unlocking via keyfile failed: %m");
+
+ goto out;
+ }
+
r = getenv_steal_erase("PASSWORD", &envpw);
if (r < 0)
return log_error_errno(r, "Failed to acquire password from environment: %m");
}
}
+out:
*ret_cd = TAKE_PTR(cd);
*ret_volume_key = TAKE_PTR(vk);
*ret_volume_key_size = vks;
return 0;
}
-static int print_dependencies(FILE *f, const char* device_path) {
+static int print_dependencies(FILE *f, const char* device_path, const char* timeout_value, bool canfail) {
int r;
+ assert(!canfail || timeout_value);
+
if (STR_IN_SET(device_path, "-", "none"))
/* None, nothing to do */
return 0;
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- fprintf(f,
- "After=%1$s\n"
- "Requires=%1$s\n", unit);
+ fprintf(f, "After=%1$s\n", unit);
+ if (canfail) {
+ fprintf(f, "Wants=%1$s\n", unit);
+ r = write_drop_in_format(arg_dest, unit, 90, "device-timeout",
+ "# Automatically generated by systemd-cryptsetup-generator \n\n"
+ "[Unit]\nJobRunningTimeoutSec=%s", timeout_value);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write device drop-in: %m");
+ } else
+ fprintf(f, "Requires=%1$s\n", unit);
} else {
/* Regular file, add mount dependency */
_cleanup_free_ char *escaped_path = specifier_escape(device_path);
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
if (key_file && !keydev) {
- r = print_dependencies(f, key_file);
+ r = print_dependencies(f, key_file,
+ keyfile_timeout_value,
+ /* canfail= */ keyfile_can_timeout > 0);
if (r < 0)
return r;
}
/* Check if a header option was specified */
if (detached_header > 0 && !headerdev) {
- r = print_dependencies(f, header_path);
+ r = print_dependencies(f, header_path,
+ NULL,
+ /* canfail= */ false); /* header is always necessary */
if (r < 0)
return r;
}
assert_se(token == r);
assert(json);
- if (pin && memchr(pin, 0, pin_size - 1))
- return crypt_log_error_errno(cd, ENOANO, "PIN must be characters string.");
-
- /* pin was passed as pin = pin, pin_size = strlen(pin). We need to add terminating
- * NULL byte to addressable memory*/
- if (pin && pin[pin_size-1] != '\0') {
- pin_string = strndup(pin, pin_size);
- if (!pin_string)
- return crypt_log_oom(cd);
- }
+ r = crypt_normalize_pin(pin, pin_size, &pin_string);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Can not normalize PIN: %m");
- return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string ?: pin, password, password_len);
+ return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string, password, password_len);
}
/*
return crypt_log_debug_errno(cd, r, TOKEN_NAME " open failed: %m.");
}
-/*
- * This function is called from within following libcryptsetup calls
- * provided conditions further below are met:
- *
- * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
- *
- * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
- * (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
- * and token is assigned to at least single keyslot).
- *
- * - if plugin defines validate function (see cryptsetup_token_validate below) it must have
- * passed the check (aka return 0)
- */
-_public_ int cryptsetup_token_open(
+_public_ int cryptsetup_token_open_pin(
struct crypt_device *cd, /* is always LUKS2 context */
int token /* is always >= 0 */,
+ const char *pin,
+ size_t pin_size,
char **password, /* freed by cryptsetup_token_buffer_free */
size_t *password_len,
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
_cleanup_free_ void *blob = NULL, *policy_hash = NULL;
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
- _cleanup_(erase_and_freep) char *base64_encoded = NULL;
+ _cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL;
+ assert(!pin || pin_size);
assert(password);
assert(password_len);
assert(token >= 0);
assert(token == r);
assert(json);
+ r = crypt_normalize_pin(pin, pin_size, &pin_string);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Can not normalize PIN: %m");
+
if (usrptr)
params = *(systemd_tpm2_plugin_params *)usrptr;
policy_hash,
policy_hash_size,
flags,
+ pin_string,
&decrypted_key,
&decrypted_key_size);
if (r < 0)
return 0;
}
+/*
+ * This function is called from within following libcryptsetup calls
+ * provided conditions further below are met:
+ *
+ * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
+ *
+ * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
+ * (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
+ * and token is assigned to at least single keyslot).
+ *
+ * - if plugin defines validate function (see cryptsetup_token_validate below) it must have
+ * passed the check (aka return 0)
+ */
+_public_ int cryptsetup_token_open(
+ struct crypt_device *cd, /* is always LUKS2 context */
+ int token /* is always >= 0 */,
+ char **password, /* freed by cryptsetup_token_buffer_free */
+ size_t *password_len,
+ void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
+
+ return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
+}
+
/*
* libcryptsetup callback for memory deallocation of 'password' parameter passed in
* any crypt_token_open_* plugin function
return 0;
}
+
+int crypt_normalize_pin(const void *pin, size_t pin_size, char **ret_pin_string) {
+
+ _cleanup_free_ char *pin_string = NULL;
+
+ assert(pin || !pin_size);
+ assert(ret_pin_string);
+
+ if (!pin) {
+ *ret_pin_string = NULL;
+ return 0;
+ }
+
+ /* Refuse embedded NULL bytes, but allow trailing NULL */
+ if (memchr(pin, 0, pin_size - 1))
+ return -EINVAL;
+
+ /* Enforce trailing NULL byte if missing */
+ pin_string = memdup_suffix0(pin, pin_size);
+ if (!pin_string)
+ return -ENOMEM;
+
+ *ret_pin_string = TAKE_PTR(pin_string);
+
+ return 0;
+}
char **ret_dump_str);
int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str);
+
+int crypt_normalize_pin(const void *pin, size_t pin_size, char **ret_pin_string);
const void *policy_hash,
size_t policy_hash_size,
TPM2Flags flags,
+ const char *pin,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
_cleanup_free_ char *auto_device = NULL;
- _cleanup_(erase_and_freep) char *pin_str = NULL;
int r;
assert(ret_decrypted_key);
device = auto_device;
}
- r = getenv_steal_erase("PIN", &pin_str);
- if (r < 0)
- return log_error_errno(r, "Failed to acquire PIN from environment: %m");
- if (!r) {
- /* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's
- * internal handling. */
- if (flags & TPM2_FLAGS_USE_PIN)
- return -EOPNOTSUPP;
- }
+ if ((flags & TPM2_FLAGS_USE_PIN) && !pin)
+ return -ENOANO;
return tpm2_unseal(
device,
pcr_mask, pcr_bank,
primary_alg,
key_data, key_data_size,
- policy_hash, policy_hash_size, pin_str,
+ policy_hash, policy_hash_size, pin,
ret_decrypted_key, ret_decrypted_key_size);
}
const void *policy_hash,
size_t policy_hash_size,
TPM2Flags flags,
+ const char *pin,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
}
#endif
-static int attach_luks2_by_fido2_via_plugin(
+static int crypt_activate_by_token_pin_ask_password(
struct crypt_device *cd,
const char *name,
+ const char *type,
usec_t until,
bool headless,
void *usrptr,
- uint32_t activation_flags) {
+ uint32_t activation_flags,
+ const char *message,
+ const char *key_name,
+ const char *credential_name) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
_cleanup_strv_free_erase_ char **pins = NULL;
int r;
- r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
+ r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
return r;
STRV_FOREACH(p, pins) {
- r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+ r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
for (;;) {
pins = strv_free_erase(pins);
- r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
+ r = ask_password_auto(message, "drive-harddisk", NULL, key_name, credential_name, until, flags, &pins);
if (r < 0)
return r;
STRV_FOREACH(p, pins) {
- r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+ r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
#endif
}
+static int attach_luks2_by_fido2_via_plugin(
+ struct crypt_device *cd,
+ const char *name,
+ usec_t until,
+ bool headless,
+ void *usrptr,
+ uint32_t activation_flags) {
+
+ return crypt_activate_by_token_pin_ask_password(
+ cd,
+ name,
+ "systemd-fido2",
+ until,
+ headless,
+ usrptr,
+ activation_flags,
+ "Please enter security token PIN:",
+ "fido2-pin",
+ "cryptsetup.fido2-pin");
+}
+
static int attach_luks_or_plain_or_bitlk_by_fido2(
struct crypt_device *cd,
const char *name,
static int attach_luks2_by_tpm2_via_plugin(
struct crypt_device *cd,
const char *name,
+ usec_t until,
+ bool headless,
uint32_t flags) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
- int r;
-
systemd_tpm2_plugin_params params = {
.search_pcr_mask = arg_tpm2_pcr_mask,
.device = arg_tpm2_device
};
- if (!crypt_token_external_path())
+ if (!libcryptsetup_plugins_support())
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Libcryptsetup has external plugins support disabled.");
- r = crypt_activate_by_token_pin(cd, name, "systemd-tpm2", CRYPT_ANY_TOKEN, NULL, 0, ¶ms, flags);
- if (r > 0) /* returns unlocked keyslot id on success */
- r = 0;
-
- return r;
+ return crypt_activate_by_token_pin_ask_password(
+ cd,
+ name,
+ "systemd-tpm2",
+ until,
+ headless,
+ ¶ms,
+ flags,
+ "Please enter TPM2 PIN:",
+ "tpm2-pin",
+ "cryptsetup.tpm2-pin");
#else
return -EOPNOTSUPP;
#endif
return -EAGAIN; /* Mangle error code: let's make any form of TPM2 failure non-fatal. */
}
} else {
- r = attach_luks2_by_tpm2_via_plugin(cd, name, flags);
+ r = attach_luks2_by_tpm2_via_plugin(cd, name, until, arg_headless, flags);
+ if (r >= 0)
+ return 0;
/* EAGAIN means: no tpm2 chip found
* EOPNOTSUPP means: no libcryptsetup plugins support */
if (r == -ENXIO)
}
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
- if (!key_file && !key_data) {
- r = crypt_activate_by_token(cd, volume, CRYPT_ANY_TOKEN, NULL, flags);
+ if (!key_file && !key_data && getenv_bool("SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE") != 0) {
+ r = crypt_activate_by_token_pin_ask_password(
+ cd,
+ volume,
+ NULL,
+ until,
+ arg_headless,
+ NULL,
+ flags,
+ "Please enter LUKS2 token PIN:",
+ "luks2-pin",
+ "cryptsetup.luks2-pin");
if (r >= 0) {
log_debug("Volume %s activated with LUKS token id %i.", volume, r);
return 0;
return log_error_errno(r, "Failed to read host timezone: %m");
(void) mkdir_parents(etc_localtime, 0755);
- if (symlink(p, etc_localtime) < 0)
- return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
+ r = symlink_atomic(p, etc_localtime);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create %s symlink: %m", etc_localtime);
log_info("%s copied.", etc_localtime);
return 0;
e = strjoina("../usr/share/zoneinfo/", arg_timezone);
(void) mkdir_parents(etc_localtime, 0755);
- if (symlink(e, etc_localtime) < 0)
- return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
+ r = symlink_atomic(e, etc_localtime);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create %s symlink: %m", etc_localtime);
log_info("%s written", etc_localtime);
return 0;
if (arg_root_password)
return 0;
- r = read_credential("passwd.hashed-password.root", (void**) &arg_root_password, NULL);
- if (r == -ENOENT) {
- r = read_credential("passwd.plaintext-password.root", (void**) &arg_root_password, NULL);
- if (r < 0)
- log_debug_errno(r, "Couldn't read credential 'passwd.{hashed|plaintext}-password.root', ignoring: %m");
- else {
- arg_root_password_is_hashed = false;
- return 0;
- }
- } else if (r < 0)
- log_debug_errno(r, "Couldn't read credential 'passwd.hashed-password.root', ignoring: %m");
- else {
- arg_root_password_is_hashed = true;
+ if (get_credential_user_password("root", &arg_root_password, &arg_root_password_is_hashed) >= 0)
return 0;
- }
if (!arg_prompt_root_password)
return 0;
return;
}
- log_info("Running request %s/start/%s", target, mode);
+ log_info("Requesting %s/start/%s", target, mode);
/* Start this unit only if we can replace basic.target with it */
r = sd_bus_call_method(bus,
#include <unistd.h>
#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-locator.h"
#include "chase-symlinks.h"
#include "fd-util.h"
#include "fileio.h"
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
+#include "process-util.h"
#include "special.h"
#include "specifier.h"
#include "stat-util.h"
MOUNT_RW_ONLY = 1 << 5,
} MountPointFlags;
+static bool arg_sysroot_check = false;
static const char *arg_dest = NULL;
static const char *arg_dest_late = NULL;
static bool arg_fstab_enabled = true;
return 0;
}
+ if (arg_sysroot_check) {
+ log_info("%s should be enabled in the initrd, will request daemon-reload.", what);
+ return true;
+ }
+
r = unit_name_from_path(what, ".swap", &name);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
return r;
}
- return 0;
+ return true;
}
static bool mount_is_network(struct mntent *me) {
mount_point_ignore(where))
return 0;
+ if (arg_sysroot_check) {
+ log_info("%s should be mounted in the initrd, will request daemon-reload.", where);
+ return true;
+ }
+
r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL);
if (r < 0)
return r;
return r;
}
- return 0;
+ return true;
+}
+
+static int do_daemon_reload(void) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r, k;
+
+ log_debug("Calling org.freedesktop.systemd1.Manager.Reload()...");
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+
+ /* We need to requeue the two targets so that any new units which previously were not part of the
+ * targets, and which we now added, will be started. */
+
+ r = 0;
+ FOREACH_STRING(unit, SPECIAL_INITRD_FS_TARGET, SPECIAL_SWAP_TARGET) {
+ log_info("Requesting %s/start/replace...", unit);
+
+ k = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartUnit",
+ &error,
+ NULL,
+ "ss", unit, "replace");
+ if (k < 0) {
+ log_error_errno(k, "Failed to (re)start %s: %s", unit, bus_error_message(&error, r));
+ if (r == 0)
+ r = k;
+ }
+ }
+
+ return r;
}
static const char* sysroot_fstab_path(void) {
if (initrd)
fstab = sysroot_fstab_path();
- else
+ else {
fstab = fstab_path();
+ assert(!arg_sysroot_check);
+ }
log_debug("Parsing %s...", fstab);
target_unit);
}
+ if (arg_sysroot_check && k > 0)
+ return true; /* We found a mount or swap that would be started… */
if (r >= 0 && k < 0)
r = k;
}
return determine_device(&arg_usr_what, arg_usr_hash, "usr");
}
-static int run(const char *dest, const char *dest_early, const char *dest_late) {
+/* If arg_sysroot_check is false, run as generator in the usual fashion.
+ * If it is true, check /sysroot/etc/fstab for any units that we'd want to mount
+ * in the initrd, and call daemon-reload. We will get reinvoked as a generator,
+ * with /sysroot/etc/fstab available, and then we can write additional units based
+ * on that file. */
+static int run_generator(void) {
int r, r2 = 0, r3 = 0;
- assert_se(arg_dest = dest);
- assert_se(arg_dest_late = dest_late);
-
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
(void) determine_root();
(void) determine_usr();
+ if (arg_sysroot_check) {
+ r = parse_fstab(true);
+ if (r == 0)
+ log_debug("Nothing interesting found, not doing daemon-reload.");
+ if (r > 0)
+ r = do_daemon_reload();
+ return r;
+ }
+
/* Always honour root= and usr= in the kernel command line if we are in an initrd */
if (in_initrd()) {
r = add_sysroot_mount();
return r < 0 ? r : r2 < 0 ? r2 : r3;
}
-DEFINE_MAIN_GENERATOR_FUNCTION(run);
+static int run(int argc, char **argv) {
+ arg_sysroot_check = invoked_as(argv, "systemd-sysroot-fstab-check");
+
+ if (arg_sysroot_check) {
+ /* Run as in systemd-sysroot-fstab-check mode */
+ log_setup();
+
+ if (strv_length(argv) > 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program takes no arguments.");
+ if (!in_initrd())
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program is only useful in the initrd.");
+ } else {
+ /* Run in generator mode */
+ log_setup_generator();
+
+ if (!IN_SET(strv_length(argv), 2, 4))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program takes one or three arguments.");
+
+ arg_dest = ASSERT_PTR(argv[1]);
+ arg_dest_late = ASSERT_PTR(argv[argc > 3 ? 3 : 1]);
+ }
+
+ return run_generator();
+}
+
+DEFINE_MAIN_FUNCTION(run);
r = sd_device_new_from_devnum(&d, 'b', devnum);
if (r < 0)
- return log_debug_errno(r, "Failed to open device: %m");
+ return log_debug_errno(r, "Failed to create device object for block device "DEVNUM_FORMAT_STR": %m",
+ DEVNUM_FORMAT_VAL(devnum));
if (sd_device_get_devname(d, &name) < 0) {
r = sd_device_get_syspath(d, &name);
else
mode = "replace-irreversibly";
- log_debug("Running request %s/start/%s", target, mode);
+ log_debug("Requesting %s/start/%s", target, mode);
r = sd_bus_call_method(
s->bus,
dropin_dirname,
"Journal\0",
config_item_perf_lookup, journald_gperf_lookup,
- CONFIG_PARSE_WARN, s, NULL);
+ CONFIG_PARSE_WARN, s, NULL, NULL);
if (r < 0)
return r;
return 0;
}
-static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, uint16_t arp_type, usec_t t, struct duid *ret_duid, size_t *ret_len) {
+static int dhcp_identifier_set_duid_llt(
+ const struct hw_addr_data *hw_addr,
+ uint16_t arp_type,
+ usec_t t,
+ struct duid *ret_duid,
+ size_t *ret_len) {
+
uint16_t time_from_2000y;
- assert(addr);
+ assert(hw_addr);
assert(ret_duid);
assert(ret_len);
- if (addr_len == 0)
+ if (hw_addr->length == 0)
return -EOPNOTSUPP;
if (arp_type == ARPHRD_ETHER)
- assert_return(addr_len == ETH_ALEN, -EINVAL);
+ assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
else if (arp_type == ARPHRD_INFINIBAND)
- assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
+ assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
else
return -EOPNOTSUPP;
unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT);
unaligned_write_be16(&ret_duid->llt.htype, arp_type);
unaligned_write_be32(&ret_duid->llt.time, time_from_2000y);
- memcpy(ret_duid->llt.haddr, addr, addr_len);
+ memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length);
- *ret_len = offsetof(struct duid, llt.haddr) + addr_len;
+ *ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length;
return 0;
}
-static int dhcp_identifier_set_duid_ll(const uint8_t *addr, size_t addr_len, uint16_t arp_type, struct duid *ret_duid, size_t *ret_len) {
- assert(addr);
+static int dhcp_identifier_set_duid_ll(
+ const struct hw_addr_data *hw_addr,
+ uint16_t arp_type,
+ struct duid *ret_duid,
+ size_t *ret_len) {
+
+ assert(hw_addr);
assert(ret_duid);
assert(ret_len);
- if (addr_len == 0)
+ if (hw_addr->length == 0)
return -EOPNOTSUPP;
if (arp_type == ARPHRD_ETHER)
- assert_return(addr_len == ETH_ALEN, -EINVAL);
+ assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
else if (arp_type == ARPHRD_INFINIBAND)
- assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
+ assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
else
return -EOPNOTSUPP;
unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL);
unaligned_write_be16(&ret_duid->ll.htype, arp_type);
- memcpy(ret_duid->ll.haddr, addr, addr_len);
+ memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length);
- *ret_len = offsetof(struct duid, ll.haddr) + addr_len;
+ *ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length;
return 0;
}
int dhcp_identifier_set_duid(
DUIDType duid_type,
- const uint8_t *addr,
- size_t addr_len,
+ const struct hw_addr_data *hw_addr,
uint16_t arp_type,
usec_t llt_time,
bool test_mode,
switch (duid_type) {
case DUID_TYPE_LLT:
- return dhcp_identifier_set_duid_llt(addr, addr_len, arp_type, llt_time, ret_duid, ret_len);
+ return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len);
case DUID_TYPE_EN:
return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len);
case DUID_TYPE_LL:
- return dhcp_identifier_set_duid_ll(addr, addr_len, arp_type, ret_duid, ret_len);
+ return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len);
case DUID_TYPE_UUID:
return dhcp_identifier_set_duid_uuid(ret_duid, ret_len);
default:
int dhcp_identifier_set_iaid(
int ifindex,
- const uint8_t *mac,
- size_t mac_len,
+ const struct hw_addr_data *hw_addr,
bool legacy_unstable_byteorder,
bool use_mac,
void *ret) {
uint64_t id;
int r;
+ assert(ifindex > 0);
+ assert(hw_addr);
+ assert(ret);
+
if (udev_available() && !use_mac) {
/* udev should be around */
id = siphash24(name, strlen(name), HASH_KEY.bytes);
else
/* fall back to MAC address if no predictable name available */
- id = siphash24(mac, mac_len, HASH_KEY.bytes);
+ id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
id32 = (id & 0xffffffff) ^ (id >> 32);
#include "sd-id128.h"
+#include "ether-addr-util.h"
#include "macro.h"
#include "sparse-endian.h"
#include "time-util.h"
int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len);
int dhcp_identifier_set_duid(
DUIDType duid_type,
- const uint8_t *addr,
- size_t addr_len,
+ const struct hw_addr_data *hw_addr,
uint16_t arp_type,
usec_t llt_time,
bool test_mode,
size_t *ret_len);
int dhcp_identifier_set_iaid(
int ifindex,
- const uint8_t *mac,
- size_t mac_len,
+ const struct hw_addr_data *hw_addr,
bool legacy_unstable_byteorder,
bool use_mac,
void *ret);
#include "sd-dhcp-client.h"
#include "dhcp-protocol.h"
+#include "ether-addr-util.h"
#include "network-common.h"
#include "socket-util.h"
typedef struct sd_dhcp_client sd_dhcp_client;
-int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
- const uint8_t *mac_addr, size_t mac_addr_len,
- const uint8_t *bcast_addr, size_t bcast_addr_len,
- uint16_t arp_type, uint16_t port);
+int dhcp_network_bind_raw_socket(
+ int ifindex,
+ union sockaddr_union *link,
+ uint32_t xid,
+ const struct hw_addr_data *hw_addr,
+ const struct hw_addr_data *bcast_addr,
+ uint16_t arp_type,
+ uint16_t port);
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
const void *packet, size_t len);
#include "socket-util.h"
#include "unaligned.h"
-static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
- uint32_t xid,
- const uint8_t *bcast_addr,
- size_t bcast_addr_len,
- const struct ether_addr *eth_mac,
- uint16_t arp_type, uint8_t dhcp_hlen,
- uint16_t port) {
+static int _bind_raw_socket(
+ int ifindex,
+ union sockaddr_union *link,
+ uint32_t xid,
+ const struct hw_addr_data *hw_addr,
+ const struct hw_addr_data *bcast_addr,
+ uint16_t arp_type,
+ uint16_t port) {
+
+ assert(ifindex > 0);
+ assert(link);
+ assert(hw_addr);
+ assert(bcast_addr);
+ assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
+
+ switch (arp_type) {
+ case ARPHRD_ETHER:
+ assert(hw_addr->length == ETH_ALEN);
+ assert(bcast_addr->length == ETH_ALEN);
+ break;
+ case ARPHRD_INFINIBAND:
+ assert(hw_addr->length == 0);
+ assert(bcast_addr->length == INFINIBAND_ALEN);
+ break;
+ default:
+ assert_not_reached();
+ }
+
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (uint8_t) hw_addr->length, 1, 0), /* address length == hw_addr->length ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
/* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
* compare chaddr for ETH_ALEN bytes. */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */
- BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */
+ BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(hw_addr->bytes)), /* X <- 4 bytes of client's MAC */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(hw_addr->bytes + 4)), /* X <- remainder of client's MAC */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */
_cleanup_close_ int s = -1;
int r;
- assert(ifindex > 0);
- assert(link);
-
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (s < 0)
return -errno;
.sll_protocol = htobe16(ETH_P_IP),
.sll_ifindex = ifindex,
.sll_hatype = htobe16(arp_type),
- .sll_halen = bcast_addr_len,
+ .sll_halen = bcast_addr->length,
};
- memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
+ /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
+ memcpy(link->ll.sll_addr, bcast_addr->bytes, bcast_addr->length);
r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
int ifindex,
union sockaddr_union *link,
uint32_t xid,
- const uint8_t *mac_addr,
- size_t mac_addr_len,
- const uint8_t *bcast_addr,
- size_t bcast_addr_len,
+ const struct hw_addr_data *hw_addr,
+ const struct hw_addr_data *bcast_addr,
uint16_t arp_type,
uint16_t port) {
- static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- /* Default broadcast address for IPoIB */
- static const uint8_t ib_bcast[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff
+ static struct hw_addr_data default_eth_bcast = {
+ .length = ETH_ALEN,
+ .ether = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+ }, default_ib_bcast = {
+ .length = INFINIBAND_ALEN,
+ .infiniband = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+ },
};
- struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
- const uint8_t *default_bcast_addr;
- size_t expected_bcast_addr_len;
- uint8_t dhcp_hlen = 0;
-
- if (arp_type == ARPHRD_ETHER) {
- assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
- memcpy(ð_mac, mac_addr, ETH_ALEN);
- dhcp_hlen = ETH_ALEN;
-
- default_bcast_addr = eth_bcast;
- expected_bcast_addr_len = ETH_ALEN;
- } else if (arp_type == ARPHRD_INFINIBAND) {
- default_bcast_addr = ib_bcast;
- expected_bcast_addr_len = INFINIBAND_ALEN;
- } else
- return -EINVAL;
- if (bcast_addr && bcast_addr_len > 0)
- assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
- else {
- bcast_addr = default_bcast_addr;
- bcast_addr_len = expected_bcast_addr_len;
+ assert(ifindex > 0);
+ assert(link);
+ assert(hw_addr);
+
+ switch (arp_type) {
+ case ARPHRD_ETHER:
+ return _bind_raw_socket(ifindex, link, xid,
+ hw_addr,
+ (bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_eth_bcast,
+ arp_type, port);
+
+ case ARPHRD_INFINIBAND:
+ return _bind_raw_socket(ifindex, link, xid,
+ &HW_ADDR_NULL,
+ (bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_ib_bcast,
+ arp_type, port);
+ default:
+ return -EINVAL;
}
-
- return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
- ð_mac, arp_type, dhcp_hlen, port);
}
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr))
#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE)
-#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage))
-#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */
-#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE)
+#define DHCP_HEADER_SIZE (int32_t)(sizeof(DHCPMessage))
+#define DHCP_MIN_MESSAGE_SIZE 576 /* the minimum internet hosts must be able to receive, see RFC 2132 Section 9.10 */
+#define DHCP_MIN_OPTIONS_SIZE (DHCP_MIN_MESSAGE_SIZE - DHCP_HEADER_SIZE)
+#define DHCP_MIN_PACKET_SIZE (DHCP_MIN_MESSAGE_SIZE + DHCP_IP_UDP_SIZE)
#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363)
enum {
};
DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
+
+int dhcp6_message_status_to_errno(DHCP6Status s) {
+ switch (s) {
+ case DHCP6_STATUS_SUCCESS:
+ return 0;
+ case DHCP6_STATUS_NO_BINDING:
+ return -EADDRNOTAVAIL;
+ default:
+ return -EINVAL;
+ }
+}
DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
+int dhcp6_message_status_to_errno(DHCP6Status s);
int ifindex,
union sockaddr_union *link,
uint32_t id,
- const uint8_t *addr, size_t addr_len,
- const uint8_t *bcaddr, size_t bcaddr_len,
+ const struct hw_addr_data *hw_addr,
+ const struct hw_addr_data *bcast_addr,
uint16_t arp_type, uint16_t port) {
int fd;
assert_se(IN_SET(client->state, DHCP6_STATE_REQUEST, DHCP6_STATE_BOUND));
break;
case DHCP6_STATE_REQUEST:
- assert_se(client->state == DHCP6_STATE_BOUND);
+ assert_se(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_SOLICITATION));
break;
default:
assert_not_reached();
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
+#include "ether-addr-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "hostname-util.h"
Set *req_opts;
bool anonymize;
be32_t last_addr;
- uint8_t mac_addr[MAX_MAC_ADDR_LEN];
- size_t mac_addr_len;
- uint8_t bcast_addr[MAX_MAC_ADDR_LEN];
- size_t bcast_addr_len;
+ struct hw_addr_data hw_addr;
+ struct hw_addr_data bcast_addr;
uint16_t arp_type;
sd_dhcp_client_id client_id;
size_t client_id_len;
int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
client->request_broadcast = broadcast;
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
assert_return(client, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
switch (option) {
const struct in_addr *last_addr) {
assert_return(client, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
if (last_addr)
client->last_addr = last_addr->s_addr;
int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
assert_return(client, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(ifindex > 0, -EINVAL);
client->ifindex = ifindex;
int sd_dhcp_client_set_mac(
sd_dhcp_client *client,
- const uint8_t *addr,
+ const uint8_t *hw_addr,
const uint8_t *bcast_addr,
size_t addr_len,
uint16_t arp_type) {
- DHCP_CLIENT_DONT_DESTROY(client);
- bool need_restart = false;
- int r;
-
assert_return(client, -EINVAL);
- assert_return(addr, -EINVAL);
- assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
- assert_return(arp_type > 0, -EINVAL);
-
- if (arp_type == ARPHRD_ETHER)
- assert_return(addr_len == ETH_ALEN, -EINVAL);
- else if (arp_type == ARPHRD_INFINIBAND)
- assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
- else
- return -EINVAL;
-
- if (client->mac_addr_len == addr_len &&
- memcmp(&client->mac_addr, addr, addr_len) == 0 &&
- (client->bcast_addr_len > 0) == !!bcast_addr &&
- (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0))
- return 0;
-
- if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
- need_restart = true;
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- }
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
+ assert_return(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND), -EINVAL);
+ assert_return(hw_addr, -EINVAL);
+ assert_return(addr_len == (arp_type == ARPHRD_ETHER ? ETH_ALEN : INFINIBAND_ALEN), -EINVAL);
- memcpy(&client->mac_addr, addr, addr_len);
- client->mac_addr_len = addr_len;
client->arp_type = arp_type;
- client->bcast_addr_len = 0;
-
- if (bcast_addr) {
- memcpy(&client->bcast_addr, bcast_addr, addr_len);
- client->bcast_addr_len = addr_len;
- }
-
- if (need_restart && client->state != DHCP_STATE_STOPPED) {
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
- }
+ hw_addr_set(&client->hw_addr, hw_addr, addr_len);
+ hw_addr_set(&client->bcast_addr, bcast_addr, bcast_addr ? addr_len : 0);
return 0;
}
const uint8_t *data,
size_t data_len) {
- DHCP_CLIENT_DONT_DESTROY(client);
- bool need_restart = false;
- int r;
-
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(data, -EINVAL);
assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
- if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
- client->client_id.type == type &&
- memcmp(&client->client_id.raw.data, data, data_len) == 0)
- return 0;
-
/* For hardware types, log debug message about unexpected data length.
*
* Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
"unexpected address length %zu",
type, data_len);
- if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Changing client ID on running DHCP "
- "client, restarting");
- need_restart = true;
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- }
-
client->client_id.type = type;
memcpy(&client->client_id.raw.data, data, data_len);
client->client_id_len = data_len + sizeof (client->client_id.type);
- if (need_restart && client->state != DHCP_STATE_STOPPED) {
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
- }
-
return 0;
}
size_t duid_len,
usec_t llt_time) {
- DHCP_CLIENT_DONT_DESTROY(client);
- int r;
size_t len;
+ int r;
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(duid_len == 0 || duid, -EINVAL);
if (duid) {
if (iaid_set)
client->client_id.ns.iaid = htobe32(iaid);
else {
- r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
- client->mac_addr_len,
+ r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
/* legacy_unstable_byteorder = */ true,
/* use_mac = */ client->test_mode,
&client->client_id.ns.iaid);
len = sizeof(client->client_id.ns.duid.type) + duid_len;
} else {
- r = dhcp_identifier_set_duid(duid_type, client->mac_addr, client->mac_addr_len,
+ r = dhcp_identifier_set_duid(duid_type, &client->hw_addr,
client->arp_type, llt_time, client->test_mode,
&client->client_id.ns.duid, &len);
if (r == -EOPNOTSUPP)
client->client_id_len = sizeof(client->client_id.type) + len +
(iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
- if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
- }
-
return 0;
}
const char *hostname) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
/* Make sure hostnames qualify as DNS and as Linux hostnames */
if (hostname &&
const char *vci) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
return free_and_strdup(&client->vendor_class_identifier, vci);
}
const char *mudurl) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(mudurl, -EINVAL);
assert_return(strlen(mudurl) <= 255, -EINVAL);
assert_return(http_url_is_valid(mudurl), -EINVAL);
char **s = NULL;
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(!strv_isempty(user_class), -EINVAL);
STRV_FOREACH(p, user_class) {
uint16_t port) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
client->port = port;
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
assert_return(client, -EINVAL);
- assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
+ assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE);
+
+ /* MTU may be changed by the acquired lease. Hence, we cannot require that the client is stopped here.
+ * Please do not add assertion for !sd_dhcp_client_is_running(client) here. */
client->mtu = mtu;
int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
client->max_attempts = max_attempts;
int r;
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(v, -EINVAL);
r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v);
int r;
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(v, -EINVAL);
r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
client->ip_service_type = type;
int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(fallback_lease_lifetime > 0, -EINVAL);
client->fallback_lease_lifetime = fallback_lease_lifetime;
_cleanup_free_ DHCPPacket *packet = NULL;
size_t optlen, optoffset, size;
- be16_t max_size;
usec_t time_now;
uint16_t secs;
int r;
return -ENOMEM;
r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
- client->arp_type, client->mac_addr_len, client->mac_addr,
+ client->arp_type, client->hw_addr.length, client->hw_addr.bytes,
optlen, &optoffset);
if (r < 0)
return r;
client->client_id.type = 255;
- r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
+ r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
/* legacy_unstable_byteorder = */ true,
/* use_mac = */ client->test_mode,
&client->client_id.ns.iaid);
*/
/* RFC7844 section 3:
SHOULD NOT contain any other option. */
- if (!client->anonymize && type != DHCP_RELEASE) {
- max_size = htobe16(size);
- r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
+ if (!client->anonymize && IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)) {
+ be16_t max_size = htobe16(MIN(client->mtu - DHCP_IP_UDP_SIZE, (uint32_t) UINT16_MAX));
+ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
2, &max_size);
if (r < 0)
client->xid = random_u32();
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
- client->mac_addr, client->mac_addr_len,
- client->bcast_addr, client->bcast_addr_len,
+ &client->hw_addr, &client->bcast_addr,
client->arp_type, client->port);
if (r < 0) {
client_stop(client, r);
client->attempt = 0;
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
- client->mac_addr, client->mac_addr_len,
- client->bcast_addr, client->bcast_addr_len,
+ &client->hw_addr, &client->bcast_addr,
client->arp_type, client->port);
if (r < 0) {
client_stop(client, r);
if (client->arp_type == ARPHRD_ETHER) {
expected_hlen = ETH_ALEN;
- expected_chaddr = &client->mac_addr[0];
+ expected_chaddr = client->hw_addr.bytes;
}
if (message->hlen != expected_hlen) {
int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
+ assert_return(sd_dhcp_client_is_running(client), -ESTALE);
assert_return(client->fd >= 0, -EINVAL);
if (!client->lease)
int sd_dhcp_client_send_release(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
- assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+ assert_return(sd_dhcp_client_is_running(client), -ESTALE);
assert_return(client->lease, -EUNATCH);
_cleanup_free_ DHCPPacket *release = NULL;
/* Fill up release IP and MAC */
release->dhcp.ciaddr = client->lease->address;
- memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+ memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length);
r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
- assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+ assert_return(sd_dhcp_client_is_running(client), -ESTALE);
assert_return(client->lease, -EUNATCH);
_cleanup_free_ DHCPPacket *release = NULL;
return r;
release->dhcp.ciaddr = client->lease->address;
- memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+ memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length);
r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
assert_return(client, -EINVAL);
assert_return(!client->event, -EBUSY);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
if (event)
client->event = sd_event_ref(event);
int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
client->event = sd_event_unref(client->event);
.state = DHCP_STATE_INIT,
.ifindex = -1,
.fd = -1,
- .mtu = DHCP_DEFAULT_MIN_SIZE,
+ .mtu = DHCP_MIN_PACKET_SIZE,
.port = DHCP_PORT_CLIENT,
.anonymize = !!anonymize,
.max_attempts = UINT64_MAX,
r = lease_parse_u16(option, len, &lease->mtu, 68);
if (r < 0)
log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
- if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
- log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
- lease->mtu = DHCP_DEFAULT_MIN_SIZE;
+ if (lease->mtu < DHCP_MIN_PACKET_SIZE) {
+ log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_MIN_PACKET_SIZE);
+ lease->mtu = DHCP_MIN_PACKET_SIZE;
}
break;
return 0;
}
- memcpy(client->hw_addr.bytes, addr, addr_len);
- client->hw_addr.length = addr_len;
client->arp_type = arp_type;
+ hw_addr_set(&client->hw_addr, addr, addr_len);
return 0;
}
client->duid_len = sizeof(client->duid.type) + duid_len;
} else {
- r = dhcp_identifier_set_duid(duid_type, client->hw_addr.bytes, client->hw_addr.length,
- client->arp_type, llt_time, client->test_mode, &client->duid, &client->duid_len);
+ r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time,
+ client->test_mode, &client->duid, &client->duid_len);
if (r == -EOPNOTSUPP)
return log_dhcp6_client_errno(client, r,
"Failed to set %s. MAC address is not set or "
if (client->iaid_set)
return 0;
- r = dhcp_identifier_set_iaid(client->ifindex, client->hw_addr.bytes, client->hw_addr.length,
+ r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
/* legacy_unstable_byteorder = */ true,
/* use_mac = */ client->test_mode,
&iaid);
client->callback(client, event, client->userdata);
}
-static void client_stop(sd_dhcp6_client *client, int error) {
- DHCP6_CLIENT_DONT_DESTROY(client);
-
+static void client_cleanup(sd_dhcp6_client *client) {
assert(client);
- client_notify(client, error);
-
client->lease = sd_dhcp6_lease_unref(client->lease);
/* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
client_set_state(client, DHCP6_STATE_STOPPED);
}
+static void client_stop(sd_dhcp6_client *client, int error) {
+ DHCP6_CLIENT_DONT_DESTROY(client);
+
+ assert(client);
+
+ client_notify(client, error);
+
+ client_cleanup(client);
+}
+
static int client_append_common_options_in_managed_mode(
sd_dhcp6_client *client,
uint8_t **opt,
req_opts = client->req_opts;
}
+ if (n == 0)
+ return 0;
+
return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
}
return log_invalid_message_type(client, message);
r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
+ if (r == -EADDRNOTAVAIL) {
+
+ /* If NoBinding status code is received, we cannot request the address anymore.
+ * Let's restart transaction from the beginning. */
+
+ if (client->state == DHCP6_STATE_REQUEST)
+ /* The lease is not acquired yet, hence it is not necessary to notify the restart. */
+ client_cleanup(client);
+ else
+ /* We need to notify the previous lease was expired. */
+ client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
+
+ return client_start_transaction(client, DHCP6_STATE_SOLICITATION);
+ }
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
if (r > 0)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+ return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
"Received %s message with non-zero status: %s%s%s",
dhcp6_message_type_to_string(message->type),
strempty(msg), isempty(msg) ? "" : ": ",
#include "dhcp-identifier.h"
#include "dhcp-internal.h"
#include "dhcp-protocol.h"
+#include "ether-addr-util.h"
#include "fd-util.h"
#include "random-util.h"
#include "tests.h"
#include "util.h"
-static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
-static uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
+static struct hw_addr_data hw_addr = {
+ .length = ETH_ALEN,
+ .ether = {{ 'A', 'B', 'C', '1', '2', '3' }},
+}, bcast_addr = {
+ .length = ETH_ALEN,
+ .ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
+};
typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
static bool verbose = true;
uint32_t iaid_legacy;
be32_t iaid;
- assert_se(dhcp_identifier_set_iaid(42, mac_addr, sizeof(mac_addr), /* legacy = */ true,
+ assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ true,
/* use_mac = */ true, &iaid_legacy) >= 0);
- assert_se(dhcp_identifier_set_iaid(42, mac_addr, sizeof(mac_addr), /* legacy = */ false,
+ assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ false,
/* use_mac = */ true, &iaid) >= 0);
/* we expect, that the MAC address was hashed. The legacy value is in native
size_t duid_len;
assert_se(dhcp_identifier_set_duid_en(/* test_mode = */ true, &duid, &duid_len) >= 0);
- assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, true, /* use_mac = */ true, &iaid) >= 0);
+ assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ true, /* use_mac = */ true, &iaid) >= 0);
assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
assert_se(len == 19);
assert_se(ip_check == 0xffff);
assert_se(discover->dhcp.xid);
- assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
+ assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
int ifindex,
union sockaddr_union *link,
uint32_t id,
- const uint8_t *addr, size_t addr_len,
- const uint8_t *bcaddr, size_t bcaddr_len,
+ const struct hw_addr_data *_hw_addr,
+ const struct hw_addr_data *_bcast_addr,
uint16_t arp_type, uint16_t port) {
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
assert_se(r >= 0);
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
- assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
+ assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
dhcp_client_set_test_mode(client, true);
assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
- memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
+ memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
callback_recv = NULL;
memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
- memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
+ memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
callback_recv = test_addr_acq_recv_request;
assert_se(r >= 0);
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
- assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
+ assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
dhcp_client_set_test_mode(client, true);
assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
sd_bus_error_setfv;
sd_device_new_child;
+ sd_device_monitor_set_description;
+ sd_device_monitor_get_description;
sd_id128_string_equal;
else
hashmap = &enumerator->nomatch_sysattr;
- /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
- * multiple times with the same sysattr but different value. */
- r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
+ r = update_match_strv(hashmap, sysattr, value, /* clear_on_null = */ true);
if (r <= 0)
return r;
assert_return(enumerator, -EINVAL);
assert_return(property, -EINVAL);
- /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
- * multiple times with the same property but different value. */
- r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
+ r = update_match_strv(&enumerator->match_property, property, value, /* clear_on_null = */ false);
if (r <= 0)
return r;
}
static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
- const char *property;
- const char *value;
+ const char *property_pattern;
+ char * const *value_patterns;
assert(enumerator);
assert(device);
+ /* Unlike device_match_sysattr(), this accepts device that has at least one matching property. */
+
if (hashmap_isempty(enumerator->match_property))
return true;
- HASHMAP_FOREACH_KEY(value, property, enumerator->match_property) {
- const char *property_dev, *value_dev;
+ HASHMAP_FOREACH_KEY(value_patterns, property_pattern, enumerator->match_property) {
+ const char *property, *value;
- FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
- if (fnmatch(property, property_dev, 0) != 0)
+ FOREACH_DEVICE_PROPERTY(device, property, value) {
+ if (fnmatch(property_pattern, property, 0) != 0)
continue;
- if (!value && !value_dev)
- return true;
-
- if (!value || !value_dev)
- continue;
-
- if (fnmatch(value, value_dev, 0) == 0)
+ if (strv_fnmatch(value_patterns, value))
return true;
}
}
if (!dir)
return -errno;
- log_debug("sd-device-enumerator: Scanning %s", path);
-
FOREACH_DIRENT_ALL(de, dir, return -errno) {
int k;
static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
int k, r = 0;
- log_debug("sd-device-enumerator: Scan all dirs");
-
k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
#include "string-util.h"
#include "strv.h"
+#define log_monitor(m, format, ...) \
+ log_debug("sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+#define log_monitor_errno(m, r, format, ...) \
+ log_debug_errno(r, "sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+#define log_device_monitor(d, m, format, ...) \
+ log_device_debug(d, "sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+#define log_device_monitor_errno(d, m, r, format, ...) \
+ log_device_debug_errno(d, r, "sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+
struct sd_device_monitor {
unsigned n_ref;
sd_event *event;
sd_event_source *event_source;
+ char *description;
sd_device_monitor_handler_t callback;
void *userdata;
};
* will not receive any messages.
*/
- log_debug("sd-device-monitor: The udev service seems not to be active, disabling the monitor");
+ log_monitor(m, "The udev service seems not to be active, disabling the monitor.");
group = MONITOR_GROUP_NONE;
}
if (fd < 0) {
sock = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
if (sock < 0)
- return log_debug_errno(errno, "sd-device-monitor: Failed to create socket: %m");
+ return log_monitor_errno(m, errno, "Failed to create socket: %m");
}
m = new(sd_device_monitor, 1);
if (fd >= 0) {
r = monitor_set_nl_address(m);
if (r < 0) {
- log_debug_errno(r, "sd-device-monitor: Failed to set netlink address: %m");
+ log_monitor_errno(m, r, "Failed to set netlink address: %m");
goto fail;
}
}
netns = ioctl(m->sock, SIOCGSKNS);
if (netns < 0)
- log_debug_errno(errno, "sd-device-monitor: Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns, ignoring: %m");
+ log_monitor_errno(m, errno, "Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns, ignoring: %m");
else {
struct stat a, b;
if (fstat(netns, &a) < 0) {
- r = log_debug_errno(errno, "sd-device-monitor: Failed to stat netns of udev netlink socket: %m");
+ r = log_monitor_errno(m, errno, "Failed to stat netns of udev netlink socket: %m");
goto fail;
}
if (ERRNO_IS_PRIVILEGE(errno))
/* If we can't access PID1's netns info due to permissions, it's fine, this is a
* safety check only after all. */
- log_debug_errno(errno, "sd-device-monitor: No permission to stat PID1's netns, unable to determine if we are in host netns, ignoring: %m");
+ log_monitor_errno(m, errno, "No permission to stat PID1's netns, unable to determine if we are in host netns, ignoring: %m");
else
- log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns, ignoring: %m");
+ log_monitor_errno(m, errno, "Failed to stat PID1's netns, ignoring: %m");
} else if (!stat_inode_same(&a, &b))
- log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events.");
+ log_monitor(m, "Netlink socket we listen on is not from host netns, we won't see device events.");
}
}
if (r < 0)
return r;
- (void) sd_event_source_set_description(m->event_source, "sd-device-monitor");
+ (void) sd_event_source_set_description(m->event_source, m->description ?: "sd-device-monitor");
return 0;
}
return m->event_source;
}
+_public_ int sd_device_monitor_set_description(sd_device_monitor *m, const char *description) {
+ int r;
+
+ assert_return(m, -EINVAL);
+
+ r = free_and_strdup(&m->description, description);
+ if (r <= 0)
+ return r;
+
+ if (m->event_source)
+ (void) sd_event_source_set_description(m->event_source, description);
+
+ return r;
+}
+
+_public_ int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret) {
+ assert_return(m, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = m->description;
+ return 0;
+}
+
int device_monitor_enable_receiving(sd_device_monitor *m) {
int r;
r = sd_device_monitor_filter_update(m);
if (r < 0)
- return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m");
+ return log_monitor_errno(m, r, "Failed to update filter: %m");
if (!m->bound) {
/* enable receiving of sender credentials */
r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
if (r < 0)
- return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m");
+ return log_monitor_errno(m, r, "Failed to set socket option SO_PASSCRED: %m");
if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0)
- return log_debug_errno(errno, "sd-device-monitor: Failed to bind monitoring socket: %m");
+ return log_monitor_errno(m, errno, "Failed to bind monitoring socket: %m");
m->bound = true;
r = monitor_set_nl_address(m);
if (r < 0)
- return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m");
+ return log_monitor_errno(m, r, "Failed to set address: %m");
}
return 0;
(void) sd_device_monitor_detach_event(m);
+ free(m->description);
hashmap_free(m->subsystem_filter);
set_free(m->tag_filter);
hashmap_free(m->match_sysattr_filter);
buflen = recvmsg(m->sock, &smsg, 0);
if (buflen < 0) {
- if (ERRNO_IS_TRANSIENT(errno))
- log_debug_errno(errno, "sd-device-monitor: Failed to receive message: %m");
+ if (!ERRNO_IS_TRANSIENT(errno))
+ log_monitor_errno(m, errno, "Failed to receive message: %m");
return -errno;
}
if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC))
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "sd-device-monitor: Invalid message length.");
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EINVAL), "Invalid message length.");
if (snl.nl.nl_groups == MONITOR_GROUP_NONE) {
/* unicast message, check if we trust the sender */
if (m->snl_trusted_sender.nl.nl_pid == 0 ||
snl.nl.nl_pid != m->snl_trusted_sender.nl.nl_pid)
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Unicast netlink message ignored.");
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Unicast netlink message ignored.");
} else if (snl.nl.nl_groups == MONITOR_GROUP_KERNEL) {
if (snl.nl.nl_pid > 0)
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Multicast kernel netlink message from PID %"PRIu32" ignored.",
+ snl.nl.nl_pid);
}
cmsg = CMSG_FIRSTHDR(&smsg);
if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: No sender credentials received, message ignored.");
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "No sender credentials received, ignoring message.");
cred = (struct ucred*) CMSG_DATA(cmsg);
if (cred->uid != 0)
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Sender uid="UID_FMT", message ignored.", cred->uid);
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Sender uid="UID_FMT", message ignored.", cred->uid);
if (streq(buf.raw, "libudev")) {
/* udev message needs proper version magic */
if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC))
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Invalid message signature (%x != %x)",
- buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Invalid message signature (%x != %x).",
+ buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
if (buf.nlh.properties_off+32 > (size_t) buflen)
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Invalid message length (%u > %zd)",
- buf.nlh.properties_off+32, buflen);
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Invalid message length (%u > %zd).",
+ buf.nlh.properties_off+32, buflen);
bufpos = buf.nlh.properties_off;
/* kernel message with header */
bufpos = strlen(buf.raw) + 1;
if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen)
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Invalid message length");
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Invalid message length.");
/* check message header */
if (!strstr(buf.raw, "@/"))
- return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
- "sd-device-monitor: Invalid message header");
+ return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+ "Invalid message header.");
}
r = device_new_from_nulstr(&device, &buf.raw[bufpos], buflen - bufpos);
if (r < 0)
- return log_debug_errno(r, "sd-device-monitor: Failed to create device from received message: %m");
+ return log_monitor_errno(m, r, "Failed to create device from received message: %m");
if (is_initialized)
device_set_is_initialized(device);
/* Skip device, if it does not pass the current filter */
r = passes_filter(m, device);
if (r < 0)
- return log_device_debug_errno(device, r, "sd-device-monitor: Failed to check received device passing filter: %m");
+ return log_device_monitor_errno(device, m, r, "Failed to check received device passing filter: %m");
if (r == 0)
- log_device_debug(device, "sd-device-monitor: Received device does not pass filter, ignoring");
+ log_device_monitor(device, m, "Received device does not pass filter, ignoring.");
else
*ret = TAKE_PTR(device);
r = device_get_properties_nulstr(device, &buf, &blen);
if (r < 0)
- return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device properties: %m");
+ return log_device_monitor_errno(device, m, r, "Failed to get device properties: %m");
if (blen < 32)
- log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
- "sd-device-monitor: Length of device property nulstr is too small to contain valid device information");
+ return log_device_monitor_errno(device, m, SYNTHETIC_ERRNO(EINVAL),
+ "Length of device property nulstr is too small to contain valid device information.");
/* fill in versioned header */
r = sd_device_get_subsystem(device, &val);
if (r < 0)
- return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device subsystem: %m");
+ return log_device_monitor_errno(device, m, r, "Failed to get device subsystem: %m");
nlh.filter_subsystem_hash = htobe32(string_hash32(val));
if (sd_device_get_devtype(device, &val) >= 0)
count = sendmsg(m->sock, &smsg, 0);
if (count < 0) {
if (!destination && errno == ECONNREFUSED) {
- log_device_debug(device, "sd-device-monitor: Passed to netlink monitor");
+ log_device_monitor(device, m, "Passed to netlink monitor.");
return 0;
} else
- return log_device_debug_errno(device, errno, "sd-device-monitor: Failed to send device to netlink monitor: %m");
+ return log_device_monitor_errno(device, m, errno, "Failed to send device to netlink monitor: %m");
}
- log_device_debug(device, "sd-device-monitor: Passed %zi byte to netlink monitor", count);
+ log_device_monitor(device, m, "Passed %zi byte to netlink monitor.", count);
return count;
}
hashmap = &m->nomatch_sysattr_filter;
/* TODO: unset m->filter_uptodate on success when we support this filter on BPF. */
- return hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
+ return update_match_strv(hashmap, sysattr, value, /* clear_on_null = */ true);
}
_public_ int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match) {
#include "device-util.h"
#include "path-util.h"
-static bool device_match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
+int update_match_strv(Hashmap **match_strv, const char *key, const char *value, bool clear_on_null) {
+ char **strv;
+ int r;
+
+ assert(match_strv);
+ assert(key);
+
+ strv = hashmap_get(*match_strv, key);
+ if (strv) {
+ if (!value) {
+ char **v;
+
+ if (strv_isempty(strv) || !clear_on_null)
+ return 0;
+
+ /* Accept all value. Clear previous assignment. */
+
+ v = new0(char*, 1);
+ if (!v)
+ return -ENOMEM;
+
+ strv_free_and_replace(strv, v);
+ } else {
+ if (strv_contains(strv, value))
+ return 0;
+
+ r = strv_extend(&strv, value);
+ if (r < 0)
+ return r;
+ }
+
+ r = hashmap_update(*match_strv, key, strv);
+ if (r < 0)
+ return r;
+
+ } else {
+ _cleanup_strv_free_ char **strv_alloc = NULL;
+ _cleanup_free_ char *key_alloc = NULL;
+
+ key_alloc = strdup(key);
+ if (!key_alloc)
+ return -ENOMEM;
+
+ strv_alloc = strv_new(value);
+ if (!strv_alloc)
+ return -ENOMEM;
+
+ r = hashmap_ensure_put(match_strv, &string_hash_ops_free_strv_free, key_alloc, strv_alloc);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(key_alloc);
+ TAKE_PTR(strv_alloc);
+ }
+
+ return 1;
+}
+
+static bool device_match_sysattr_value(sd_device *device, const char *sysattr, char * const *patterns) {
const char *value;
assert(device);
if (sd_device_get_sysattr_value(device, sysattr, &value) < 0)
return false;
- if (!match_value)
- return true;
-
- if (fnmatch(match_value, value, 0) == 0)
- return true;
-
- return false;
+ return strv_fnmatch_or_empty(patterns, value, 0);
}
bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr) {
+ char * const *patterns;
const char *sysattr;
- const char *value;
assert(device);
- HASHMAP_FOREACH_KEY(value, sysattr, match_sysattr)
- if (!device_match_sysattr_value(device, sysattr, value))
+ HASHMAP_FOREACH_KEY(patterns, sysattr, match_sysattr)
+ if (!device_match_sysattr_value(device, sysattr, patterns))
return false;
- HASHMAP_FOREACH_KEY(value, sysattr, nomatch_sysattr)
- if (device_match_sysattr_value(device, sysattr, value))
+ HASHMAP_FOREACH_KEY(patterns, sysattr, nomatch_sysattr)
+ if (device_match_sysattr_value(device, sysattr, patterns))
return false;
return true;
#define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
#define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
+int update_match_strv(Hashmap **match_strv, const char *key, const char *value, bool clear_on_null);
bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr);
bool device_match_parent(sd_device *device, Set *match_parent, Set *nomatch_parent);
assert(device);
assert(_syspath);
- /* must be a subdirectory of /sys */
- if (!path_startswith(_syspath, "/sys/"))
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "sd-device: Syspath '%s' is not a subdirectory of /sys",
- _syspath);
-
if (verify) {
_cleanup_close_ int fd = -1;
+ /* The input path maybe a symlink located outside of /sys. Let's try to chase the symlink at first.
+ * The primary usecase is that e.g. /proc/device-tree is a symlink to /sys/firmware/devicetree/base.
+ * By chasing symlinks in the path at first, we can call sd_device_new_from_path() with such path. */
r = chase_symlinks(_syspath, NULL, 0, &syspath, &fd);
if (r == -ENOENT)
/* the device does not exist (any more?) */
"sd-device: the syspath \"%s\" is outside of sysfs, refusing.", syspath);
}
} else {
+ /* must be a subdirectory of /sys */
+ if (!path_startswith(_syspath, "/sys/"))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "sd-device: Syspath '%s' is not a subdirectory of /sys",
+ _syspath);
+
syspath = strdup(_syspath);
if (!syspath)
return log_oom_debug();
return 0;
}
-_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
+static int device_new_from_syspath(sd_device **ret, const char *syspath, bool strict) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
assert_return(ret, -EINVAL);
assert_return(syspath, -EINVAL);
+ if (strict && !path_startswith(syspath, "/sys/"))
+ return -EINVAL;
+
r = device_new_aux(&device);
if (r < 0)
return r;
return 0;
}
+_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
+ return device_new_from_syspath(ret, syspath, /* strict = */ true);
+}
+
static int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_free_ char *syspath = NULL;
if (path_startswith(path, "/dev"))
return sd_device_new_from_devname(ret, path);
- return sd_device_new_from_syspath(ret, path);
+ return device_new_from_syspath(ret, path, /* strict = */ false);
}
int device_set_devtype(sd_device *device, const char *devtype) {
#include "device-private.h"
#include "device-util.h"
#include "macro.h"
+#include "path-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "tests.h"
assert_se(sd_device_get_syspath(loopback, &syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
assert_se(device_monitor_send_device(monitor_server, monitor_client, loopback) >= 0);
assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
if (subsystem_filter) {
assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, false) >= 0);
assert_se(sd_device_get_syspath(d, &p) >= 0);
assert_se(sd_device_get_subsystem(d, &s) >= 0);
+ assert_se(device_add_property(d, "ACTION", "add") >= 0);
+ assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
+
log_device_debug(d, "Sending device subsystem:%s syspath:%s", s, p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
}
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, "TEST_SD_DEVICE_MONITOR") >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
FOREACH_DEVICE(e, d) {
assert_se(sd_device_get_syspath(d, &p) >= 0);
+ assert_se(device_add_property(d, "ACTION", "add") >= 0);
+ assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
+
log_device_debug(d, "Sending device syspath:%s", p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
}
static void test_sysattr_filter(sd_device *device, const char *sysattr) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
- const char *syspath, *subsystem, *sysattr_value;
+ const char *syspath, *sysattr_value;
sd_device *d;
log_device_info(device, "/* %s(%s) */", __func__, sysattr);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
- assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
assert_se(sd_device_get_sysattr_value(device, sysattr, &sysattr_value) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
- /* The sysattr filter is not implemented in BPF yet, so the below device_monito_send_device()
- * may cause EAGAIN. So, let's also filter devices with subsystem. */
- assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
assert_se(sd_device_monitor_filter_add_match_sysattr(monitor_client, sysattr, sysattr_value, true) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
assert_se(sd_device_enumerator_add_match_sysattr(e, sysattr, sysattr_value, false) >= 0);
assert_se(sd_device_get_syspath(d, &p) >= 0);
+ assert_se(device_add_property(d, "ACTION", "add") >= 0);
+ assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
+
log_device_debug(d, "Sending device syspath:%s", p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+
+ /* The sysattr filter is not implemented in BPF yet. So, sending multiple devices may fills up
+ * buffer and device_monitor_send_device() may return EAGAIN. Let's send one device here,
+ * which should be filtered out by the receiver. */
+ break;
}
log_device_info(device, "Sending device syspath:%s", syspath);
static void test_parent_filter(sd_device *device) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
- const char *syspath, *subsystem;
+ const char *syspath, *parent_syspath;
sd_device *parent, *d;
int r;
log_device_info(device, "/* %s */", __func__);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
- assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
r = sd_device_get_parent(device, &parent);
if (r < 0)
return (void) log_device_info(device, "Device does not have parent, skipping.");
+ assert_se(sd_device_get_syspath(parent, &parent_syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
- /* The parent filter is not implemented in BPF yet, so the below device_monito_send_device()
- * may cause EAGAIN. So, let's also filter devices with subsystem. */
- assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
assert_se(sd_device_monitor_filter_add_match_parent(monitor_client, parent, true) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
FOREACH_DEVICE(e, d) {
const char *p;
assert_se(sd_device_get_syspath(d, &p) >= 0);
+ if (path_startswith(p, parent_syspath))
+ continue;
+
+ assert_se(device_add_property(d, "ACTION", "add") >= 0);
+ assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
log_device_debug(d, "Sending device syspath:%s", p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+
+ /* The parent filter is not implemented in BPF yet. So, sending multiple devices may fills up
+ * buffer and device_monitor_send_device() may return EAGAIN. Let's send one device here,
+ * which should be filtered out by the receiver. */
+ break;
}
log_device_info(device, "Sending device syspath:%s", syspath);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+ assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
- assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, "hoge", NULL) >= 0);
assert_se(sd_device_monitor_filter_update(monitor_client) >= 0);
#include <ctype.h>
#include <fcntl.h>
+#include <unistd.h>
#include "device-enumerator-private.h"
#include "device-internal.h"
#include "hashmap.h"
#include "nulstr-util.h"
#include "path-util.h"
+#include "rm-rf.h"
#include "string-util.h"
#include "tests.h"
#include "time-util.h"
+#include "tmpfile-util.h"
static void test_sd_device_one(sd_device *d) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
assert_se(n_new_dev + n_removed_dev <= 10);
}
+TEST(sd_device_enumerator_add_match_sysattr) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
+ int ifindex;
+
+ assert_se(sd_device_enumerator_new(&e) >= 0);
+ assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+ assert_se(sd_device_enumerator_add_match_subsystem(e, "net", true) >= 0);
+ assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true) >= 0);
+ assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "hoge", true) >= 0);
+ assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "foo", true) >= 0);
+ assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "bar", false) >= 0);
+ assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "baz", false) >= 0);
+
+ dev = sd_device_enumerator_get_device_first(e);
+ assert_se(dev);
+ assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
+ assert_se(ifindex == 1);
+
+ assert_se(!sd_device_enumerator_get_device_next(e));
+}
+
+TEST(sd_device_enumerator_add_match_property) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
+ int ifindex;
+
+ assert_se(sd_device_enumerator_new(&e) >= 0);
+ assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+ assert_se(sd_device_enumerator_add_match_subsystem(e, "net", true) >= 0);
+ assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true) >= 0);
+ assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", "1*") >= 0);
+ assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", "hoge") >= 0);
+ assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", NULL) >= 0);
+ assert_se(sd_device_enumerator_add_match_property(e, "AAAAA", "BBBB") >= 0);
+ assert_se(sd_device_enumerator_add_match_property(e, "FOOOO", NULL) >= 0);
+
+ dev = sd_device_enumerator_get_device_first(e);
+ assert_se(dev);
+ assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
+ assert_se(ifindex == 1);
+}
+
TEST(sd_device_new_from_nulstr) {
const char *devlinks =
"/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
}
}
+TEST(sd_device_new_from_path) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
+ sd_device *dev;
+ int r;
+
+ assert_se(mkdtemp_malloc("/tmp/test-sd-device.XXXXXXX", &tmpdir) >= 0);
+
+ assert_se(sd_device_enumerator_new(&e) >= 0);
+ assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+ assert_se(sd_device_enumerator_add_match_subsystem(e, "block", true) >= 0);
+ assert_se(sd_device_enumerator_add_nomatch_sysname(e, "loop*") >= 0);
+ assert_se(sd_device_enumerator_add_match_property(e, "DEVNAME", "*") >= 0);
+
+ FOREACH_DEVICE(e, dev) {
+ _cleanup_(sd_device_unrefp) sd_device *d = NULL;
+ const char *syspath, *devpath, *sysname, *s;
+ _cleanup_free_ char *path = NULL;
+
+ assert_se(sd_device_get_sysname(dev, &sysname) >= 0);
+
+ log_debug("%s(%s)", __func__, sysname);
+
+ assert_se(sd_device_get_syspath(dev, &syspath) >= 0);
+ assert_se(sd_device_new_from_path(&d, syspath) >= 0);
+ assert_se(sd_device_get_syspath(d, &s) >= 0);
+ assert_se(streq(s, syspath));
+ d = sd_device_unref(d);
+
+ assert_se(sd_device_get_devname(dev, &devpath) >= 0);
+ r = sd_device_new_from_path(&d, devpath);
+ if (r >= 0) {
+ assert_se(sd_device_get_syspath(d, &s) >= 0);
+ assert_se(streq(s, syspath));
+ d = sd_device_unref(d);
+ } else
+ assert_se(r == -ENODEV || ERRNO_IS_PRIVILEGE(r));
+
+ assert_se(path = path_join(tmpdir, sysname));
+ assert_se(symlink(syspath, path) >= 0);
+ assert_se(sd_device_new_from_path(&d, path) >= 0);
+ assert_se(sd_device_get_syspath(d, &s) >= 0);
+ assert_se(streq(s, syspath));
+ }
+}
+
DEFINE_TEST_MAIN(LOG_INFO);
log_struct(LOG_INFO,
LOG_MESSAGE("System shutdown has been cancelled"),
"ACTION=%s", handle_action_to_string(a->handle),
- "MESSAGE_ID=" SD_MESSAGE_LOGIND_SHUTDOWN_CANCELED_STR,
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_CANCELED_STR,
username ? "OPERATOR=%s" : NULL, username);
utmp_wall("System shutdown has been cancelled",
#include "alloc-util.h"
#include "bus-util.h"
+#include "daemon-util.h"
#include "fd-util.h"
#include "logind-session-dbus.h"
#include "logind-session-device.h"
}
void session_device_free(SessionDevice *sd) {
- int r;
-
assert(sd);
/* Make sure to remove the pushed fd. */
- if (sd->pushed_fd) {
- r = sd_notifyf(false,
- "FDSTOREREMOVE=1\n"
- "FDNAME=session-%s-device-%u-%u",
- sd->session->id, major(sd->dev), minor(sd->dev));
- if (r < 0)
- log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
- }
+ if (sd->pushed_fd)
+ (void) notify_remove_fd_warnf("session-%s-device-%u-%u", sd->session->id, major(sd->dev), minor(sd->dev));
session_device_stop(sd);
session_device_notify(sd, SESSION_DEVICE_RELEASE);
}
int session_device_save(SessionDevice *sd) {
- _cleanup_free_ char *m = NULL;
const char *id;
int r;
id = sd->session->id;
assert(*(id + strcspn(id, "-\n")) == '\0');
- r = asprintf(&m, "FDSTORE=1\n"
- "FDNAME=session-%s-device-%u-%u\n",
- id, major(sd->dev), minor(sd->dev));
- if (r < 0)
- return r;
-
- r = sd_pid_notify_with_fds(0, false, m, &sd->fd, 1);
+ r = notify_push_fdf(sd->fd, "session-%s-device-%u-%u", id, major(sd->dev), minor(sd->dev));
if (r < 0)
return r;
log_struct(level,
LOG_MESSAGE("%s", l),
"ACTION=%s", handle_action_to_string(m->scheduled_shutdown_action->handle),
- "MESSAGE_ID=" SD_MESSAGE_LOGIND_SHUTDOWN_STR,
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_SCHEDULED_STR,
username ? "OPERATOR=%s" : NULL, username);
if (m->enable_wall_messages)
static int manager_attach_fds(Manager *m) {
_cleanup_strv_free_ char **fdnames = NULL;
- int r, n;
+ int n;
/* Upon restart, PID1 will send us back all fds of session devices that we previously opened. Each
* file descriptor is associated with a given session. The session ids are passed through FDNAMES. */
if (deliver_fd(m, fdnames[i], fd) >= 0)
continue;
- /* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd */
- safe_close(fd);
-
- /* Remove from fdstore as well */
- r = sd_notifyf(false,
- "FDSTOREREMOVE=1\n"
- "FDNAME=%s", fdnames[i]);
- if (r < 0)
- log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
+ /* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd
+ * and remove it from fdstore. */
+ close_and_notify_warn(fd, fdnames[i]);
}
return 0;
static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit, const char *field) {
uint64_t val;
int r;
+ bool is_cpu_weight;
+ is_cpu_weight = streq(field, "CPUWeight");
if (isempty(limit))
return PAM_SUCCESS;
- r = cg_weight_parse(limit, &val);
+ r = is_cpu_weight ? cg_cpu_weight_parse(limit, &val) : cg_weight_parse(limit, &val);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", field, "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
- } else if (streq(field, "CPUWeight"))
+ } else if (is_cpu_weight)
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit);
else
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit);
Tun.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
Tun.User, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, user_name)
Tun.Group, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, group_name)
+Tun.KeepCarrier, config_parse_bool, 0, offsetof(TunTap, keep_fd)
Tap.OneQueue, config_parse_warn_compat, DISABLED_LEGACY, 0
Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
Tap.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
Tap.User, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, user_name)
Tap.Group, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, group_name)
+Tap.KeepCarrier, config_parse_bool, 0, offsetof(TunTap, keep_fd)
Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)
return;
}
+ if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
+ NETDEV_VTABLE(netdev)->drop(netdev);
+
netdev->state = NETDEV_STATE_LINGER;
log_netdev_debug(netdev, "netdev removed");
config_item_perf_lookup, network_netdev_gperf_lookup,
CONFIG_PARSE_WARN,
netdev_raw,
+ NULL,
NULL);
if (r < 0)
return r; /* config_parse_many() logs internally. */
NETDEV_VTABLE(netdev)->sections,
config_item_perf_lookup, network_netdev_gperf_lookup,
CONFIG_PARSE_WARN,
- netdev, NULL);
+ netdev, NULL, NULL);
if (r < 0)
return r; /* config_parse_many() logs internally. */
* to be set != 0. */
void (*init)(NetDev *n);
+ /* This is called when the interface is removed. */
+ void (*drop)(NetDev *n);
+
/* This should free all kind-specific variables. It should be
* idempotent. */
void (*done)(NetDev *n);
#include <linux/if_tun.h>
#include "alloc-util.h"
+#include "daemon-util.h"
#include "fd-util.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "socket-util.h"
#include "tuntap.h"
#include "user-util.h"
#define TUN_DEV "/dev/net/tun"
-static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
- TunTap *t;
-
+static TunTap* TUNTAP(NetDev *netdev) {
assert(netdev);
- assert(netdev->ifname);
- assert(ifr);
-
- if (netdev->kind == NETDEV_KIND_TAP) {
- t = TAP(netdev);
- ifr->ifr_flags |= IFF_TAP;
- } else {
- t = TUN(netdev);
- ifr->ifr_flags |= IFF_TUN;
+
+ switch (netdev->kind) {
+ case NETDEV_KIND_TAP:
+ return TAP(netdev);
+ case NETDEV_KIND_TUN:
+ return TUN(netdev);
+ default:
+ return NULL;
}
+}
- if (!t->packet_info)
- ifr->ifr_flags |= IFF_NO_PI;
+static void *close_fd_ptr(void *p) {
+ safe_close(PTR_TO_FD(p));
+ return NULL;
+}
- if (t->multi_queue)
- ifr->ifr_flags |= IFF_MULTI_QUEUE;
+DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops, char, string_hash_func, string_compare_func, free, void, close_fd_ptr);
- if (t->vnet_hdr)
- ifr->ifr_flags |= IFF_VNET_HDR;
+int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
+ _cleanup_free_ char *tuntap_name = NULL;
+ const char *p;
+ int r;
+
+ assert(m);
+ assert(fd >= 0);
+ assert(name);
+
+ p = startswith(name, "tuntap-");
+ if (!p)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received unknown fd (%s).", name);
+
+ if (!ifname_valid(p))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received tuntap fd with invalid name (%s).", p);
- strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
+ tuntap_name = strdup(p);
+ if (!tuntap_name)
+ return log_oom_debug();
+ r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
+ if (r < 0)
+ return log_debug_errno(r, "Failed to store tuntap fd: %m");
+
+ TAKE_PTR(tuntap_name);
return 0;
}
-static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
+void manager_clear_unmanaged_tuntap_fds(Manager *m) {
+ char *name;
+ void *p;
+
+ assert(m);
+
+ while ((p = hashmap_steal_first_key_and_value(m->tuntap_fds_by_name, (void**) &name))) {
+ close_and_notify_warn(PTR_TO_FD(p), name);
+ name = mfree(name);
+ }
+}
+
+static int tuntap_take_fd(NetDev *netdev) {
+ _cleanup_free_ char *name = NULL;
+ void *p;
+ int r;
+
+ assert(netdev);
+ assert(netdev->manager);
+
+ r = link_get_by_name(netdev->manager, netdev->ifname, NULL);
+ if (r < 0)
+ return r;
+
+ p = hashmap_remove2(netdev->manager->tuntap_fds_by_name, netdev->ifname, (void**) &name);
+ if (!p)
+ return -ENOENT;
+
+ log_netdev_debug(netdev, "Found file descriptor in fd store.");
+ return PTR_TO_FD(p);
+}
+
+static int netdev_create_tuntap(NetDev *netdev) {
_cleanup_close_ int fd = -1;
- TunTap *t = NULL;
- const char *user;
- const char *group;
- uid_t uid;
- gid_t gid;
+ struct ifreq ifr = {};
+ TunTap *t;
int r;
assert(netdev);
- assert(ifr);
+ t = TUNTAP(netdev);
+ assert(t);
- fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
+ fd = TAKE_FD(t->fd);
if (fd < 0)
- return log_netdev_error_errno(netdev, errno, "Failed to open tun dev: %m");
-
- if (ioctl(fd, TUNSETIFF, ifr) < 0)
- return log_netdev_error_errno(netdev, errno, "TUNSETIFF failed on tun dev: %m");
+ fd = tuntap_take_fd(netdev);
+ if (fd < 0)
+ fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
+ if (fd < 0)
+ return log_netdev_error_errno(netdev, errno, "Failed to open " TUN_DEV ": %m");
if (netdev->kind == NETDEV_KIND_TAP)
- t = TAP(netdev);
+ ifr.ifr_flags |= IFF_TAP;
else
- t = TUN(netdev);
+ ifr.ifr_flags |= IFF_TUN;
- assert(t);
+ if (!t->packet_info)
+ ifr.ifr_flags |= IFF_NO_PI;
+
+ if (t->multi_queue)
+ ifr.ifr_flags |= IFF_MULTI_QUEUE;
+
+ if (t->vnet_hdr)
+ ifr.ifr_flags |= IFF_VNET_HDR;
+
+ strncpy(ifr.ifr_name, netdev->ifname, IFNAMSIZ-1);
+
+ if (ioctl(fd, TUNSETIFF, &ifr) < 0)
+ return log_netdev_error_errno(netdev, errno, "TUNSETIFF failed: %m");
if (t->user_name) {
- user = t->user_name;
+ const char *user = t->user_name;
+ uid_t uid;
r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
if (ioctl(fd, TUNSETOWNER, uid) < 0)
- return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed on tun dev: %m");
+ return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed: %m");
}
if (t->group_name) {
- group = t->group_name;
+ const char *group = t->group_name;
+ gid_t gid;
r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
if (ioctl(fd, TUNSETGROUP, gid) < 0)
- return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed on tun dev: %m");
+ return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed: %m");
}
if (ioctl(fd, TUNSETPERSIST, 1) < 0)
- return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed on tun dev: %m");
+ return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed: %m");
+
+ if (t->keep_fd) {
+ t->fd = TAKE_FD(fd);
+ (void) notify_push_fdf(t->fd, "tuntap-%s", netdev->ifname);
+ }
return 0;
}
-static int netdev_create_tuntap(NetDev *netdev) {
- struct ifreq ifr = {};
- int r;
+static void tuntap_init(NetDev *netdev) {
+ TunTap *t;
- r = netdev_fill_tuntap_message(netdev, &ifr);
- if (r < 0)
- return r;
+ assert(netdev);
+ t = TUNTAP(netdev);
+ assert(t);
- return netdev_tuntap_add(netdev, &ifr);
+ t->fd = -1;
}
-static void tuntap_done(NetDev *netdev) {
- TunTap *t = NULL;
+static void tuntap_drop(NetDev *netdev) {
+ TunTap *t;
assert(netdev);
+ t = TUNTAP(netdev);
+ assert(t);
- if (netdev->kind == NETDEV_KIND_TUN)
- t = TUN(netdev);
- else
- t = TAP(netdev);
+ t->fd = close_and_notify_warn(t->fd, netdev->ifname);
+}
+static void tuntap_done(NetDev *netdev) {
+ TunTap *t;
+
+ assert(netdev);
+ t = TUNTAP(netdev);
assert(t);
+ t->fd = safe_close(t->fd);
t->user_name = mfree(t->user_name);
t->group_name = mfree(t->group_name);
}
.object_size = sizeof(TunTap),
.sections = NETDEV_COMMON_SECTIONS "Tun\0",
.config_verify = tuntap_verify,
+ .init = tuntap_init,
+ .drop = tuntap_drop,
.done = tuntap_done,
.create = netdev_create_tuntap,
.create_type = NETDEV_CREATE_INDEPENDENT,
.object_size = sizeof(TunTap),
.sections = NETDEV_COMMON_SECTIONS "Tap\0",
.config_verify = tuntap_verify,
+ .init = tuntap_init,
+ .drop = tuntap_drop,
.done = tuntap_done,
.create = netdev_create_tuntap,
.create_type = NETDEV_CREATE_INDEPENDENT,
struct TunTap {
NetDev meta;
+ int fd;
char *user_name;
char *group_name;
bool multi_queue;
bool packet_info;
bool vnet_hdr;
+ bool keep_fd;
};
DEFINE_NETDEV_CAST(TUN, TunTap);
DEFINE_NETDEV_CAST(TAP, TunTap);
extern const NetDevVTable tun_vtable;
extern const NetDevVTable tap_vtable;
+
+int manager_add_tuntap_fd(Manager *m, int fd, const char *name);
+void manager_clear_unmanaged_tuntap_fds(Manager *m);
bool address_is_ready(const Address *a) {
assert(a);
- if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
+ if (!ipv4acd_bound(a))
return false;
- if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
+ if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
return false;
- if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
+ if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
return false;
if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
if (!link_is_ready_to_configure(link, false))
return false;
- if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
+ if (!ipv4acd_bound(address))
return false;
/* Refuse adding more than the limit */
} else {
existing->source = address->source;
existing->provider = address->provider;
+ existing->duplicate_address_detection = address->duplicate_address_detection;
existing->lifetime_valid_usec = address->lifetime_valid_usec;
existing->lifetime_preferred_usec = address->lifetime_preferred_usec;
if (consume_object)
* To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
AddressFamily duplicate_address_detection;
sd_ipv4acd *acd;
+ bool acd_bound;
/* Called when address become ready */
address_ready_callback_t callback;
int address_compare_func(const Address *a1, const Address *a2);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
-static inline void address_enter_probing(Address *address) {
- address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
-}
-static inline void address_cancel_probing(Address *address) {
- address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
-}
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
#include <linux/if_arp.h>
#include "bus-error.h"
+#include "bus-locator.h"
#include "dhcp-identifier.h"
#include "dhcp-internal.h"
#include "dhcp6-internal.h"
m->product_uuid_requested = false;
- r = sd_bus_call_method_async(
+ r = bus_call_method_async(
m->bus,
NULL,
- "org.freedesktop.hostname1",
- "/org/freedesktop/hostname1",
- "org.freedesktop.hostname1",
+ bus_hostname,
"GetProductUUID",
get_product_uuid_handler,
m,
}
int dhcp4_update_mac(Link *link) {
+ bool restart;
int r;
assert(link);
if (!link->dhcp_client)
return 0;
- r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.bytes,
+ restart = sd_dhcp_client_is_running(link->dhcp_client);
+
+ r = sd_dhcp_client_stop(link->dhcp_client);
+ if (r < 0)
+ return r;
+
+ r = sd_dhcp_client_set_mac(link->dhcp_client,
+ link->hw_addr.bytes,
link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
link->hw_addr.length, link->iftype);
if (r < 0)
return r;
- return dhcp4_set_client_identifier(link);
+ r = dhcp4_set_client_identifier(link);
+ if (r < 0)
+ return r;
+
+ if (restart) {
+ r = sd_dhcp_client_start(link->dhcp_client);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
}
int dhcp4_start(Link *link) {
return true;
}
+static bool address_ipv4acd_enabled(Address *address) {
+ assert(address);
+ assert(address->link);
+
+ if (address->family != AF_INET)
+ return false;
+
+ if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
+ return false;
+
+ /* Currently, only static and DHCP4 addresses are supported. */
+ if (!IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4))
+ return false;
+
+ if (!link_ipv4acd_supported(address->link))
+ return false;
+
+ return true;
+}
+
+bool ipv4acd_bound(const Address *address) {
+ assert(address);
+
+ if (!address->acd)
+ return true;
+
+ return address->acd_bound;
+}
+
static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
int r;
assert(link);
assert(address);
- /* Prevent form the address being freed. */
- address_enter_probing(address);
-
if (!address_exists(address))
return 0; /* Not assigned. */
if (r < 0)
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
- /* make the address will be freed. */
- address_cancel_probing(address);
-
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
return 0;
}
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
+ address->acd_bound = false;
+
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
if (r < 0)
break;
case SD_IPV4ACD_EVENT_BIND:
+ address->acd_bound = true;
+
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
-
- address_cancel_probing(address);
break;
case SD_IPV4ACD_EVENT_CONFLICT:
+ address->acd_bound = false;
+
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
}
-int ipv4acd_configure(Address *address) {
- Link *link;
- int r;
-
+static int address_ipv4acd_start(Address *address) {
assert(address);
+ assert(address->link);
- link = ASSERT_PTR(address->link);
-
- if (address->family != AF_INET)
+ if (!address->acd)
return 0;
- if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
+ if (sd_ipv4acd_is_running(address->acd))
return 0;
- if (!link_ipv4acd_supported(link))
+ if (!link_has_carrier(address->link))
return 0;
- /* Currently, only static and DHCP4 addresses are supported. */
- assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
+ return sd_ipv4acd_start(address->acd, true);
+}
- if (address->acd) {
- address_enter_probing(address);
+int ipv4acd_configure(Address *address) {
+ Link *link;
+ int r;
+
+ assert(address);
+
+ link = ASSERT_PTR(address->link);
+
+ if (!address_ipv4acd_enabled(address)) {
+ address->acd = sd_ipv4acd_unref(address->acd);
+ address->acd_bound = false;
return 0;
}
+ if (address->acd)
+ return address_ipv4acd_start(address);
+
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
if (r < 0)
return r;
- if (link_has_carrier(link)) {
- r = sd_ipv4acd_start(address->acd, true);
- if (r < 0)
- return r;
- }
-
- address_enter_probing(address);
- return 0;
+ return address_ipv4acd_start(address);
}
int ipv4acd_update_mac(Link *link) {
assert(link);
SET_FOREACH(address, link->addresses) {
- if (!address->acd)
- continue;
-
- if (sd_ipv4acd_is_running(address->acd))
- continue;
-
- r = sd_ipv4acd_start(address->acd, true);
+ r = address_ipv4acd_start(address);
if (r < 0)
return r;
}
typedef struct Link Link;
bool link_ipv4acd_supported(Link *link);
+bool ipv4acd_bound(const Address *address);
int ipv4acd_configure(Address *address);
int ipv4acd_update_mac(Link *link);
int ipv4acd_start(Link *link);
#include "strv.h"
#include "tc.h"
#include "tmpfile-util.h"
+#include "tuntap.h"
#include "udev-util.h"
#include "util.h"
#include "vrf.h"
#include <linux/nexthop.h>
#include <linux/nl80211.h>
-#include "sd-daemon.h"
#include "sd-netlink.h"
#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-locator.h"
#include "bus-log-control-api.h"
#include "bus-polkit.h"
#include "bus-util.h"
#include "conf-parser.h"
+#include "daemon-util.h"
#include "def.h"
#include "device-private.h"
#include "device-util.h"
#include "sysctl-util.h"
#include "tclass.h"
#include "tmpfile-util.h"
+#include "tuntap.h"
#include "udev-util.h"
/* use 128 MB for receive socket kernel queue. */
return 0;
}
-static int systemd_netlink_fd(void) {
- int n, fd, rtnl_fd = -EINVAL;
+static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) {
+ _cleanup_strv_free_ char **names = NULL;
+ int n, rtnl_fd = -1;
- n = sd_listen_fds(true);
- if (n <= 0)
+ assert(m);
+ assert(ret_rtnl_fd);
+
+ n = sd_listen_fds_with_names(/* unset_environment = */ true, &names);
+ if (n < 0)
+ return n;
+
+ if (strv_length(names) != (size_t) n)
return -EINVAL;
- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+ for (int i = 0; i < n; i++) {
+ int fd = i + SD_LISTEN_FDS_START;
+
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
- if (rtnl_fd >= 0)
- return -EINVAL;
+ if (rtnl_fd >= 0) {
+ log_debug("Received multiple netlink socket, ignoring.");
+ safe_close(fd);
+ continue;
+ }
rtnl_fd = fd;
+ continue;
}
- return rtnl_fd;
+ if (manager_add_tuntap_fd(m, fd, names[i]) >= 0)
+ continue;
+
+ if (m->test_mode)
+ safe_close(fd);
+ else
+ close_and_notify_warn(fd, names[i]);
+ }
+
+ *ret_rtnl_fd = rtnl_fd;
+ return 0;
}
static int manager_connect_genl(Manager *m) {
return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter);
}
-static int manager_connect_rtnl(Manager *m) {
- int fd, r;
+static int manager_connect_rtnl(Manager *m, int fd) {
+ _unused_ _cleanup_close_ int fd_close = fd;
+ int r;
assert(m);
- fd = systemd_netlink_fd();
+ /* This takes input fd. */
+
if (fd < 0)
r = sd_netlink_open(&m->rtnl);
else
r = sd_netlink_open_fd(&m->rtnl, fd);
if (r < 0)
return r;
+ TAKE_FD(fd_close);
/* Bump receiver buffer, but only if we are not called via socket activation, as in that
* case systemd sets the receive buffer size for us, and the value in the .socket unit
}
int manager_setup(Manager *m) {
+ _cleanup_close_ int rtnl_fd = -1;
int r;
assert(m);
if (r < 0)
return r;
- r = manager_connect_rtnl(m);
+ r = manager_listen_fds(m, &rtnl_fd);
+ if (r < 0)
+ return r;
+
+ r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd));
if (r < 0)
return r;
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
+ m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name);
+
m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
if (r < 0)
return r;
+ manager_clear_unmanaged_tuntap_fds(m);
+
r = network_load(m, &m->networks);
if (r < 0)
return r;
return 0;
}
- r = sd_bus_call_method_async(
+ r = bus_call_method_async(
m->bus,
NULL,
- "org.freedesktop.hostname1",
- "/org/freedesktop/hostname1",
- "org.freedesktop.hostname1",
+ bus_hostname,
"SetHostname",
set_hostname_handler,
m,
return 0;
}
- r = sd_bus_call_method_async(
+ r = bus_call_method_async(
m->bus,
NULL,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
+ bus_timedate,
"SetTimezone",
set_timezone_handler,
m,
FirewallContext *fw_ctx;
OrderedSet *request_queue;
+
+ Hashmap *tuntap_fds_by_name;
};
int manager_new(Manager **ret, bool test_mode);
config_item_perf_lookup, network_network_gperf_lookup,
CONFIG_PARSE_WARN,
network,
- &network->stats_by_path);
+ &network->stats_by_path,
+ NULL);
if (r < 0)
return r; /* config_parse_many() logs internally. */
return r;
if (link->network->use_bpdu >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu);
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, !link->network->use_bpdu);
if (r < 0)
return r;
}
}
if (link->network->allow_port_to_be_root >= 0) {
- r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root);
+ r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, !link->network->allow_port_to_be_root);
if (r < 0)
return r;
}
assert(phys_port_ifindex > 0);
assert(virt_port_ifindex > 0);
- /* This sets ifindices only whenn both interfaces are already managed by us. */
+ /* This sets ifindices only when both interfaces are already managed by us. */
r = link_get_by_index(manager, phys_port_ifindex, &phys_link);
if (r < 0)
int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
static const char* states[] = {
- [LOG2U(NETWORK_CONFIG_STATE_PROBING)] = "probing",
[LOG2U(NETWORK_CONFIG_STATE_REQUESTING)] = "requesting",
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)] = "configured",
} NetworkConfigSource;
typedef enum NetworkConfigState {
- NETWORK_CONFIG_STATE_PROBING = 1 << 0, /* address is probing by IPv4ACD */
- NETWORK_CONFIG_STATE_REQUESTING = 1 << 1, /* request is queued */
- NETWORK_CONFIG_STATE_CONFIGURING = 1 << 2, /* e.g. address_configure() is called, but no response is received yet */
- NETWORK_CONFIG_STATE_CONFIGURED = 1 << 3, /* e.g. address_configure() is called and received a response from kernel.
+ NETWORK_CONFIG_STATE_REQUESTING = 1 << 0, /* request is queued */
+ NETWORK_CONFIG_STATE_CONFIGURING = 1 << 1, /* e.g. address_configure() is called, but no response is received yet */
+ NETWORK_CONFIG_STATE_CONFIGURED = 1 << 2, /* e.g. address_configure() is called and received a response from kernel.
* Note that address may not be ready yet, so please use address_is_ready()
* to check whether the address can be usable or not. */
- NETWORK_CONFIG_STATE_MARKED = 1 << 4, /* used GC'ing the old config */
- NETWORK_CONFIG_STATE_REMOVING = 1 << 5, /* e.g. address_remove() is called, but no response is received yet */
+ NETWORK_CONFIG_STATE_MARKED = 1 << 3, /* used GC'ing the old config */
+ NETWORK_CONFIG_STATE_REMOVING = 1 << 4, /* e.g. address_remove() is called, but no response is received yet */
} NetworkConfigState;
static inline usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
- if (IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT)) /* TC_H_CLSACT == TC_H_INGRESS */
- return true;
+ /* TC_H_CLSACT == TC_H_INGRESS */
+ if (!IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT) &&
+ link_find_tclass(link, qdisc->parent, NULL) < 0)
+ return false;
+
+ if (QDISC_VTABLE(qdisc) &&
+ QDISC_VTABLE(qdisc)->is_ready &&
+ QDISC_VTABLE(qdisc)->is_ready(qdisc, link) <= 0)
+ return false;
- return link_find_tclass(link, qdisc->parent, NULL) >= 0;
+ return true;
}
static int qdisc_process_request(Request *req, Link *link, QDisc *qdisc) {
int (*init)(QDisc *qdisc);
int (*fill_message)(Link *link, QDisc *qdisc, sd_netlink_message *m);
int (*verify)(QDisc *qdisc);
+ int (*is_ready)(QDisc *qdisc, Link *link);
} QDiscVTable;
extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX];
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "macro.h"
+#include "networkd-link.h"
#include "parse-util.h"
#include "string-util.h"
#include "teql.h"
return free_and_replace(qdisc->tca_kind, tca_kind);
}
+static int trivial_link_equalizer_is_ready(QDisc *qdisc, Link *link) {
+ Link *teql;
+
+ assert(qdisc);
+ assert(qdisc->tca_kind);
+ assert(link);
+ assert(link->manager);
+
+ if (link_get_by_name(link->manager, qdisc->tca_kind, &teql) < 0)
+ return false;
+
+ return link_is_ready_to_configure(teql, /* allow_unmanaged = */ true);
+}
+
const QDiscVTable teql_vtable = {
.object_size = sizeof(TrivialLinkEqualizer),
.verify = trivial_link_equalizer_verify,
+ .is_ready = trivial_link_equalizer_is_ready,
};
int config_parse_trivial_link_equalizer_id(
MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO|MOUNT_MKDIR }, /* skipped if above was mounted */
{ "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
MOUNT_FATAL|MOUNT_MKDIR }, /* skipped if above was mounted */
- { "tmpfs", "/dev", "tmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_STRICTATIME,
+ { "tmpfs", "/dev", "tmpfs", "mode=755" TMPFS_LIMITS_PRIVATE_DEV, MS_NOSUID|MS_STRICTATIME,
MOUNT_FATAL|MOUNT_MKDIR },
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777" NESTED_TMPFS_LIMITS, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
MOUNT_FATAL|MOUNT_MKDIR },
SD_BUS_PARAM(fd),
bus_method_dump_by_fd,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_SIGNAL_WITH_NAMES("Killed",
+ "ss",
+ SD_BUS_PARAM(cgroup)
+ SD_BUS_PARAM(reason),
+ 0),
SD_BUS_VTABLE_END
};
r = cg_path_get_owner_uid(message.path, &cg_uid);
if (r < 0) {
- log_debug("Failed to get cgroup %s owner uid: %m", message.path);
+ log_debug_errno(r, "Failed to get cgroup %s owner uid: %m", message.path);
continue;
}
if (r < 0)
log_notice_errno(r, "Failed to kill any cgroup(s) based on swap: %m");
else {
- if (selected && r > 0)
+ if (selected && r > 0) {
log_notice("Killed %s due to memory used (%"PRIu64") / total (%"PRIu64") and "
"swap used (%"PRIu64") / total (%"PRIu64") being more than "
PERMYRIAD_AS_PERCENT_FORMAT_STR,
m->system_context.mem_used, m->system_context.mem_total,
m->system_context.swap_used, m->system_context.swap_total,
PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad));
+
+ /* send dbus signal */
+ (void) sd_bus_emit_signal(m->bus,
+ "/org/freedesktop/oom1",
+ "org.freedesktop.oom1.Manager",
+ "Killed",
+ "ss",
+ selected,
+ "memory-used");
+ }
return 0;
}
}
* it. In either case, go through the event loop again and select a new candidate if
* pressure is still high. */
m->mem_pressure_post_action_delay_start = usec_now;
- if (selected && r > 0)
+ if (selected && r > 0) {
log_notice("Killed %s due to memory pressure for %s being %lu.%02lu%% > %lu.%02lu%%"
" for > %s with reclaim activity",
selected, t->path,
LOADAVG_INT_SIDE(t->memory_pressure.avg10), LOADAVG_DECIMAL_SIDE(t->memory_pressure.avg10),
LOADAVG_INT_SIDE(t->mem_pressure_limit), LOADAVG_DECIMAL_SIDE(t->mem_pressure_limit),
FORMAT_TIMESPAN(m->default_mem_pressure_duration_usec, USEC_PER_SEC));
+
+ /* send dbus signal */
+ (void) sd_bus_emit_signal(m->bus,
+ "/org/freedesktop/oom1",
+ "org.freedesktop.oom1.Manager",
+ "Killed",
+ "ss",
+ selected,
+ "memory-pressure");
+ }
return 0;
}
}
static const char *arg_node = NULL;
static char *arg_root = NULL;
static char *arg_image = NULL;
-static char *arg_definitions = NULL;
+static char **arg_definitions = NULL;
static bool arg_discard = true;
static bool arg_can_factory_reset = false;
static int arg_factory_reset = -1;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
-STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
struct Partition {
char *definition_path;
+ char **drop_in_files;
sd_id128_t type_uuid;
sd_id128_t current_uuid, new_uuid;
free(p->current_label);
free(p->new_label);
free(p->definition_path);
+ strv_free(p->drop_in_files);
if (p->current_partition)
fdisk_unref_partition(p->current_partition);
return 0;
}
-static int partition_read_definition(Partition *p, const char *path) {
+static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
ConfigTableItem table[] = {
{ "Partition", "Type", config_parse_type, 0, &p->type_uuid },
{}
};
int r;
+ _cleanup_free_ char *filename = NULL;
+ const char* dropin_dirname;
- r = config_parse(NULL, path, NULL,
- "Partition\0",
- config_item_table_lookup, table,
- CONFIG_PARSE_WARN,
- p,
- NULL);
+ r = path_extract_filename(path, &filename);
+ if (r < 0)
+ return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);;
+
+ dropin_dirname = strjoina(filename, ".d");
+
+ r = config_parse_many(
+ STRV_MAKE_CONST(path),
+ conf_file_dirs,
+ dropin_dirname,
+ "Partition\0",
+ config_item_table_lookup, table,
+ CONFIG_PARSE_WARN,
+ p,
+ NULL,
+ &p->drop_in_files);
if (r < 0)
return r;
static int context_read_definitions(
Context *context,
- const char *directory,
+ char **directories,
const char *root) {
_cleanup_strv_free_ char **files = NULL;
Partition *last = NULL;
int r;
+ const char *const *dirs;
assert(context);
- if (directory)
- r = conf_files_list_strv(&files, ".conf", NULL, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char**) STRV_MAKE(directory));
- else
- r = conf_files_list_strv(&files, ".conf", root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char**) CONF_PATHS_STRV("repart.d"));
+ dirs = (const char* const*) (directories ?: CONF_PATHS_STRV("repart.d"));
+
+ r = conf_files_list_strv(&files, ".conf", directories ? NULL : root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate *.conf files: %m");
if (!p->definition_path)
return log_oom();
- r = partition_read_definition(p, *f);
+ r = partition_read_definition(p, *f, dirs);
if (r < 0)
return r;
_cleanup_(table_unrefp) Table *t = NULL;
uint64_t sum_padding = 0, sum_size = 0;
int r;
+ const size_t dropin_files_col = 13;
+ bool no_dropin_files = true;
if ((arg_json_format_flags & JSON_FORMAT_OFF) && context->n_partitions == 0) {
log_info("Empty partition table.");
return 0;
}
- t = table_new("type", "label", "uuid", "file", "node", "offset", "old size", "raw size", "size", "old padding", "raw padding", "padding", "activity");
+ t = table_new("type", "label", "uuid", "file", "node", "offset", "old size", "raw size", "size", "old padding", "raw padding", "padding", "activity", "drop-in files");
if (!t)
return log_oom();
if (!DEBUG_LOGGING) {
if (arg_json_format_flags & JSON_FORMAT_OFF)
(void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
- (size_t) 8, (size_t) 11);
+ (size_t) 8, (size_t) 11, dropin_files_col);
else
(void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
- (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12);
+ (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12,
+ dropin_files_col);
}
(void) table_set_align_percent(t, table_get_cell(t, 0, 5), 100);
TABLE_UINT64, p->current_padding == UINT64_MAX ? 0 : p->current_padding,
TABLE_UINT64, p->new_padding,
TABLE_STRING, padding_change, TABLE_SET_COLOR, !p->partitions_next && sum_padding > 0 ? ansi_underline() : NULL,
- TABLE_STRING, activity ?: "unchanged");
+ TABLE_STRING, activity ?: "unchanged",
+ TABLE_STRV, p->drop_in_files);
if (r < 0)
return table_log_add_error(r);
+
+ no_dropin_files = no_dropin_files && strv_isempty(p->drop_in_files);
}
if ((arg_json_format_flags & JSON_FORMAT_OFF) && (sum_padding > 0 || sum_size > 0)) {
TABLE_EMPTY,
TABLE_EMPTY,
TABLE_STRING, b,
+ TABLE_EMPTY,
TABLE_EMPTY);
if (r < 0)
return table_log_add_error(r);
}
+ if (no_dropin_files) {
+ r = table_hide_column_from_display(t, dropin_files_col);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set columns to display: %m");
+ }
+
return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
}
arg_pretty = r;
break;
- case ARG_DEFINITIONS:
- r = parse_path_argument(optarg, false, &arg_definitions);
+ case ARG_DEFINITIONS: {
+ _cleanup_free_ char *path = NULL;
+ r = parse_path_argument(optarg, false, &path);
if (r < 0)
return r;
+ if (strv_consume(&arg_definitions, TAKE_PTR(path)) < 0)
+ return log_oom();
break;
+ }
case ARG_SIZE: {
uint64_t parsed, rounded;
if (!context)
return log_oom();
+ strv_uniq(arg_definitions);
+
r = context_read_definitions(context, arg_definitions, arg_root);
if (r < 0)
return r;
"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=help
"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=pretty
"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=short
+
+echo "### Testing drop-in overrides ###"
+
+mkdir -p "$D/definitions-overrides"
+
+cat >"$D/definitions-overrides/root.conf" <<EOF
+[Partition]
+Type=swap
+SizeMaxBytes=64M
+UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
+EOF
+
+mkdir -p "$D/definitions-overrides/root.conf.d"
+
+cat >"$D/definitions-overrides/root.conf.d/override1.conf" <<EOF
+[Partition]
+Label=label1
+SizeMaxBytes=32M
+EOF
+
+cat >"$D/definitions-overrides/root.conf.d/override2.conf" <<EOF
+[Partition]
+Label=label2
+EOF
+
+rm -f test-drop-in-image
+
+JSON_OUTPUT=$("$repart" --definitions="$D/definitions-overrides" --dry-run=yes --empty=create --size=100M --json=pretty test-drop-in-image)
+
+diff <(echo "$JSON_OUTPUT") - <<EOF
+[
+ {
+ "type" : "swap",
+ "label" : "label2",
+ "uuid" : "837c3d67-21b3-478e-be82-7e7f83bf96d3",
+ "file" : "root.conf",
+ "node" : "test-drop-in-image1",
+ "offset" : 1048576,
+ "old_size" : 0,
+ "raw_size" : 33554432,
+ "old_padding" : 0,
+ "raw_padding" : 0,
+ "activity" : "create",
+ "drop-in_files" : [
+ "$D/definitions-overrides/root.conf.d/override1.conf",
+ "$D/definitions-overrides/root.conf.d/override2.conf"
+ ]
+ }
+]
+EOF
+
+echo "### Testing list of definitions directories ###"
+
+mkdir -p "$D/definitions1"
+
+cat >"$D/definitions1/root1.conf" <<EOF
+[Partition]
+Type=swap
+SizeMaxBytes=32M
+UUID=7b93d1f2-595d-4ce3-b0b9-837fbd9e63b0
+Label=label1
+EOF
+
+mkdir -p "$D/definitions2"
+
+cat >"$D/definitions2/root2.conf" <<EOF
+[Partition]
+Type=swap
+SizeMaxBytes=32M
+UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
+Label=label2
+EOF
+
+rm -f test-definitions
+
+JSON_OUTPUT=$("$repart" --definitions="$D/definitions1" --definitions="$D/definitions2" --dry-run=yes --empty=create --size=100M --json=pretty test-definitions)
+
+diff <(echo "$JSON_OUTPUT") - <<EOF
+[
+ {
+ "type" : "swap",
+ "label" : "label1",
+ "uuid" : "7b93d1f2-595d-4ce3-b0b9-837fbd9e63b0",
+ "file" : "root1.conf",
+ "node" : "test-definitions1",
+ "offset" : 1048576,
+ "old_size" : 0,
+ "raw_size" : 33554432,
+ "old_padding" : 0,
+ "raw_padding" : 0,
+ "activity" : "create"
+ },
+ {
+ "type" : "swap",
+ "label" : "label2",
+ "uuid" : "837c3d67-21b3-478e-be82-7e7f83bf96d3",
+ "file" : "root2.conf",
+ "node" : "test-definitions2",
+ "offset" : 34603008,
+ "old_size" : 0,
+ "raw_size" : 33554432,
+ "old_padding" : 0,
+ "raw_padding" : 0,
+ "activity" : "create"
+ }
+]
+EOF
return bus_log_create_error(r);
/* Reloading the daemon may take long, hence set a longer timeout here */
- r = sd_bus_call(*bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+ r = sd_bus_call(*bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
if (r < 0)
return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
if (!arg_now)
return 0;
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
method,
&error,
&reply,
assert(s);
- dot = strchr(s, '.');
+ dot = strrchr(s, '.');
if (dot) {
_cleanup_free_ char *iface = NULL;
config_item_perf_lookup, resolved_dnssd_gperf_lookup,
CONFIG_PARSE_WARN,
service,
+ NULL,
NULL);
if (r < 0)
return r;
return bus_log_create_error(r);
}
- r = bus_append_unit_property_assignment_many(m, t, properties);
- if (r < 0)
- return r;
-
- return 0;
+ return bus_append_unit_property_assignment_many(m, t, properties);
}
static int transient_cgroup_set_properties(sd_bus_message *m) {
.interface = "org.freedesktop.timedate1"
};
+const BusLocator* const bus_hostname = &(BusLocator){
+ .destination = "org.freedesktop.hostname1",
+ .path = "/org/freedesktop/hostname1",
+ .interface = "org.freedesktop.hostname1"
+};
+
/* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface strings encapsulated
* within a single struct. */
int bus_call_method_async(
extern const BusLocator* const bus_resolve_mgr;
extern const BusLocator* const bus_systemd_mgr;
extern const BusLocator* const bus_timedate;
+extern const BusLocator* const bus_hostname;
/* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface strings encapsulated
* within a single struct. */
bus_print_property_value(name, expected_value, flags, s);
- } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
+ } else if (STR_IN_SET(name, "CPUWeight", "StartupCPUWeight") && u == CGROUP_WEIGHT_IDLE)
+ bus_print_property_value(name, expected_value, flags, "idle");
+
+ else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
(STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
(STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
(STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == UINT64_MAX) ||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "bus-locator.h"
#include "bus-unit-procs.h"
#include "glyph-util.h"
#include "hashmap.h"
prefix = strempty(prefix);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"GetUnitProcesses",
error,
&reply,
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
+DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "CPUWeight",
- "StartupCPUWeight",
- "IOWeight",
+ "StartupCPUWeight"))
+ return bus_append_cg_cpu_weight_parse(m, field, eq);
+
+ if (STR_IN_SET(field, "IOWeight",
"StartupIOWeight"))
return bus_append_cg_weight_parse(m, field, eq);
case UNIT_TARGET:
case UNIT_DEVICE:
case UNIT_SWAP:
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Not supported unit type");
+ break;
default:
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Invalid unit type");
+ assert_not_reached();
}
r = bus_append_unit_property(m, field, eq);
return 0;
}
+int cg_cpu_weight_parse(const char *s, uint64_t *ret) {
+ if (streq_ptr(s, "idle"))
+ return *ret = CGROUP_WEIGHT_IDLE;
+ return cg_weight_parse(s, ret);
+}
+
int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
uint64_t u;
int r;
bool cg_is_hybrid_wanted(void);
int cg_weight_parse(const char *s, uint64_t *ret);
+int cg_cpu_weight_parse(const char *s, uint64_t *ret);
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
int cg_blkio_weight_parse(const char *s, uint64_t *ret);
const void *table,
ConfigParseFlags flags,
void *userdata,
- Hashmap **ret_stats_by_path) {
+ Hashmap **ret_stats_by_path,
+ char ***ret_dropin_files) {
_cleanup_strv_free_ char **files = NULL;
int r;
if (r < 0)
return r;
- return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
+ r = config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
+ if (r < 0)
+ return r;
+
+ if (ret_dropin_files)
+ *ret_dropin_files = TAKE_PTR(files);
+
+ return 0;
}
static int dropins_get_stats_by_path(
const void *table,
ConfigParseFlags flags,
void *userdata,
- Hashmap **ret_stats_by_path); /* possibly NULL */
+ Hashmap **ret_stats_by_path, /* possibly NULL */
+ char ***ret_drop_in_files); /* possibly NULL */
int config_get_stats_by_path(
const char *suffix,
(char**) ret, ret_size);
}
+int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed) {
+ _cleanup_(erase_and_freep) char *creds_password = NULL;
+ _cleanup_free_ char *cn = NULL;
+ int r;
+
+ /* Try to pick up the password for this account via the credentials logic */
+ cn = strjoin("passwd.hashed-password.", username);
+ if (!cn)
+ return -ENOMEM;
+
+ r = read_credential(cn, (void**) &creds_password, NULL);
+ if (r == -ENOENT) {
+ free(cn);
+ cn = strjoin("passwd.plaintext-password.", username);
+ if (!cn)
+ return -ENOMEM;
+
+ r = read_credential(cn, (void**) &creds_password, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+ else
+ *ret_is_hashed = false;
+ } else if (r < 0)
+ log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+ else
+ *ret_is_hashed = true;
+
+ *ret_password = TAKE_PTR(creds_password);
+
+ return r;
+}
+
#if HAVE_OPENSSL
#define CREDENTIAL_HOST_SECRET_SIZE 4096
int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size);
+int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed);
+
/* The four modes we support: keyed only by on-disk key, only by TPM2 HMAC key, and by the combination of
* both, as well as one with a fixed zero length key if TPM2 is missing (the latter of course provides no
* authenticity or confidentiality, but is still useful for integrity protection, and makes things simpler
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "daemon-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "string-util.h"
+
+static int notify_remove_fd_warn(const char *name) {
+ int r;
+
+ assert(name);
+
+ r = sd_notifyf(/* unset_environment = */ false,
+ "FDSTOREREMOVE=1\n"
+ "FDNAME=%s", name);
+ if (r < 0)
+ return log_warning_errno(r,
+ "Failed to remove file descriptor \"%s\" from the store, ignoring: %m",
+ name);
+
+ return 0;
+}
+
+int notify_remove_fd_warnf(const char *format, ...) {
+ _cleanup_free_ char *p = NULL;
+ va_list ap;
+ int r;
+
+ assert(format);
+
+ va_start(ap, format);
+ r = vasprintf(&p, format, ap);
+ va_end(ap);
+ if (r < 0)
+ return log_oom();
+
+ return notify_remove_fd_warn(p);
+}
+
+int close_and_notify_warn(int fd, const char *name) {
+ if (name)
+ (void) notify_remove_fd_warn(name);
+
+ return safe_close(fd);
+}
+
+static int notify_push_fd(int fd, const char *name) {
+ _cleanup_free_ char *state = NULL;
+
+ assert(fd >= 0);
+ assert(name);
+
+ state = strjoin("FDSTORE=1\n"
+ "FDNAME=", name);
+ if (!state)
+ return -ENOMEM;
+
+ return sd_pid_notify_with_fds(0, /* unset_environment = */ false, state, &fd, 1);
+}
+
+int notify_push_fdf(int fd, const char *format, ...) {
+ _cleanup_free_ char *name = NULL;
+ va_list ap;
+ int r;
+
+ assert(fd >= 0);
+ assert(format);
+
+ va_start(ap, format);
+ r = vasprintf(&name, format, ap);
+ va_end(ap);
+ if (r < 0)
+ return -ENOMEM;
+
+ return notify_push_fd(fd, name);
+}
#include "sd-daemon.h"
+#include "macro.h"
+
#define NOTIFY_READY "READY=1\n" "STATUS=Processing requests..."
#define NOTIFY_STOPPING "STOPPING=1\n" "STATUS=Shutting down..."
if (*p)
(void) sd_notify(false, *p);
}
+
+int notify_remove_fd_warnf(const char *format, ...) _printf_(1, 2);
+int close_and_notify_warn(int fd, const char *name);
+int notify_push_fdf(int fd, const char *format, ...) _printf_(2, 3);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
+#include "architecture.h"
#include "env-util.h"
#include "extension-release.h"
#include "log.h"
const char *host_sysext_scope,
char **extension_release) {
- const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
+ const char *extension_release_id = NULL, *extension_release_sysext_level = NULL, *extension_architecture = NULL;
assert(name);
assert(!isempty(host_os_release_id));
}
}
+ /* When the architecture field is present and not '_any' it must match the host - for now just look at uname but in
+ * the future we could check if the kernel also supports 32 bit or binfmt has a translator set up for the architecture */
+ extension_architecture = strv_env_pairs_get(extension_release, "ARCHITECTURE");
+ if (!isempty(extension_architecture) && !streq(extension_architecture, "_any") &&
+ !streq(architecture_to_string(uname_architecture()), extension_architecture)) {
+ log_debug("Extension '%s' is for architecture '%s', but deployed on top of '%s'.",
+ name, extension_architecture, architecture_to_string(uname_architecture()));
+ return 0;
+ }
+
extension_release_id = strv_env_pairs_get(extension_release, "ID");
if (isempty(extension_release_id)) {
- log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
+ log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s' or be '_any'",
name, host_os_release_id);
return 0;
}
+ /* A sysext with no host OS dependency (static binaries or scripts) can match
+ * '_any' host OS, and VERSION_ID or SYSEXT_LEVEL are not required anywhere */
+ if (streq(extension_release_id, "_any")) {
+ log_debug("Extension '%s' matches '_any' OS.", name);
+ return 1;
+ }
+
if (!streq(host_os_release_id, extension_release_id)) {
log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
name, extension_release_id, host_os_release_id);
"DefaultDependencies=no\n"
"BindsTo=%%i.mount\n"
"Conflicts=shutdown.target\n"
- "After=%%i.mount\n"
+ "After=systemd-repart.service %%i.mount\n"
"Before=shutdown.target%s%s\n",
program_invocation_short_name,
target ? " " : "",
return 0;
}
-bool hwdb_validate(sd_hwdb *hwdb) {
+bool hwdb_should_reload(sd_hwdb *hwdb) {
bool found = false;
const char* p;
struct stat st;
#include "sd-hwdb.h"
-bool hwdb_validate(sd_hwdb *hwdb);
+bool hwdb_should_reload(sd_hwdb *hwdb);
int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat);
int hwdb_query(const char *modalias, const char *root);
'creds-util.h',
'cryptsetup-util.c',
'cryptsetup-util.h',
+ 'daemon-util.c',
'daemon-util.h',
'data-fd-util.c',
'data-fd-util.h',
#include "errno-util.h"
#include "macro.h"
-/* 4MB for contents of regular files, 1m inodes for directories, symbolic links and device nodes, using
- * large storage array systems as a baseline */
-#define TMPFS_LIMITS_DEV ",size=4m,nr_inodes=1m"
+/* The limit used for /dev itself. 4MB should be enough since device nodes and symlinks don't
+ * consume any space and udev isn't supposed to create regular file either. There's no limit on the
+ * max number of inodes since such limit is hard to guess especially on large storage array
+ * systems. */
+#define TMPFS_LIMITS_DEV ",size=4m"
+
+/* The limit used for /dev in private namespaces. 4MB for contents of regular files. The number of
+ * inodes should be relatively low in private namespaces but for now use a 64k limit. */
+#define TMPFS_LIMITS_PRIVATE_DEV ",size=4m,nr_inodes=64k"
/* Very little, if any use expected */
#define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k"
{ "v249", NAMING_V249 },
{ "v250", NAMING_V250 },
{ "v251", NAMING_V251 },
+ { "v252", NAMING_V252 },
/* … add more schemes here, as the logic to name devices is updated … */
EXTRA_NET_NAMING_MAP
NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
NAMING_XEN_VIF = 1 << 13, /* Generate names for Xen netfront devices */
NAMING_BRIDGE_MULTIFUNCTION_SLOT = 1 << 14, /* Use PCI hotplug slot information associated with bridge, but only if PCI device is multifunction */
+ NAMING_DEVICETREE_ALIASES = 1 << 15, /* Generate names from devicetree aliases */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
+ NAMING_V252 = NAMING_V251 | NAMING_DEVICETREE_ALIASES,
EXTRA_NET_NAMING_SCHEMES
#include <syslog.h>
#include <unistd.h>
+#include "sd-device.h"
+
#include "alloc-util.h"
#include "blockdev-util.h"
#include "btrfs-util.h"
#include "conf-parser.h"
#include "def.h"
+#include "device-util.h"
#include "devnum-util.h"
#include "env-util.h"
#include "errno-util.h"
#include "strv.h"
#include "time-util.h"
+#define BATTERY_LOW_CAPACITY_LEVEL 5
#define DISCHARGE_RATE_FILEPATH "/var/lib/systemd/sleep/battery_discharge_percentage_rate_per_hour"
#define BATTERY_DISCHARGE_RATE_HASH_KEY SD_ID128_MAKE(5f,9a,20,18,38,76,46,07,8d,36,58,0b,bb,c4,e0,63)
+static void *CAPACITY_TO_PTR(int capacity) {
+ assert(capacity >= 0);
+ assert(capacity <= 100);
+ return INT_TO_PTR(capacity + 1);
+}
+
+static int PTR_TO_CAPACITY(void *p) {
+ int capacity = PTR_TO_INT(p) - 1;
+ assert(capacity >= 0);
+ assert(capacity <= 100);
+ return capacity;
+}
+
int parse_sleep_config(SleepConfig **ret_sleep_config) {
_cleanup_(free_sleep_configp) SleepConfig *sc = NULL;
int allow_suspend = -1, allow_hibernate = -1,
return 0;
}
-/* If battery percentage capacity is less than equal to 5% return success */
-int battery_is_low(void) {
+/* Get the list of batteries */
+static int battery_enumerator_new(sd_device_enumerator **ret) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
int r;
- /* We have not used battery capacity_level since value is set to full
- * or Normal in case acpi is not working properly. In case of no battery
- * 0 will be returned and system will be suspended for 1st cycle then hibernated */
+ assert(ret);
- r = read_battery_capacity_percentage();
- if (r == -ENOENT)
- return false;
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_subsystem(e, "power_supply", /* match= */ true);
+ if (r < 0)
+ return r;
+
+ r = sd_device_enumerator_add_match_property(e, "POWER_SUPPLY_TYPE", "Battery");
if (r < 0)
- return r;
+ return r;
+
+ *ret = TAKE_PTR(e);
- return r <= 5;
+ return 0;
+}
+
+static int get_capacity_by_name(Hashmap *capacities_by_name, const char *name) {
+ void *p;
+
+ assert(capacities_by_name);
+ assert(name);
+
+ p = hashmap_get(capacities_by_name, name);
+ if (!p)
+ return -ENOENT;
+
+ return PTR_TO_CAPACITY(p);
}
/* Battery percentage capacity fetched from capacity file and if in range 0-100 then returned */
-int read_battery_capacity_percentage(void) {
- _cleanup_free_ char *bat_cap = NULL;
+static int read_battery_capacity_percentage(sd_device *dev) {
+ const char *power_supply_capacity;
int battery_capacity, r;
- r = read_one_line_file("/sys/class/power_supply/BAT0/capacity", &bat_cap);
- if (r == -ENOENT)
- return log_debug_errno(r, "/sys/class/power_supply/BAT0/capacity is unavailable. Assuming no battery exists: %m");
+ assert(dev);
+
+ r = sd_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY", &power_supply_capacity);
if (r < 0)
- return log_debug_errno(r, "Failed to read /sys/class/power_supply/BAT0/capacity: %m");
+ return log_device_debug_errno(dev, r, "Failed to read battery capacity: %m");
- r = safe_atoi(bat_cap, &battery_capacity);
+ r = safe_atoi(power_supply_capacity, &battery_capacity);
if (r < 0)
- return log_debug_errno(r, "Failed to parse battery capacity: %m");
+ return log_device_debug_errno(dev, r, "Failed to parse battery capacity: %m");
if (battery_capacity < 0 || battery_capacity > 100)
- return log_debug_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid battery capacity");
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid battery capacity");
return battery_capacity;
}
-/* Read file path and return hash of value in that file */
-static int get_battery_identifier(const char *filepath, struct siphash *ret) {
- _cleanup_free_ char *value = NULL;
+/* If battery percentage capacity is less than equal to 5% return success */
+int battery_is_low(void) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
+ int r;
+
+ /* We have not used battery capacity_level since value is set to full
+ * or Normal in case acpi is not working properly. In case of no battery
+ * 0 will be returned and system will be suspended for 1st cycle then hibernated */
+
+ r = battery_enumerator_new(&e);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+ FOREACH_DEVICE(e, dev) {
+ r = read_battery_capacity_percentage(dev);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to get battery capacity, ignoring: %m");
+ continue;
+ }
+ if (r > BATTERY_LOW_CAPACITY_LEVEL)
+ return false;
+ }
+
+ return true;
+}
+
+/* Store current capacity of each battery before suspension and timestamp */
+int fetch_batteries_capacity_by_name(Hashmap **ret) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ _cleanup_(hashmap_freep) Hashmap *batteries_capacity_by_name = NULL;
+ sd_device *dev;
int r;
- assert(filepath);
assert(ret);
- r = read_one_line_file(filepath, &value);
+ batteries_capacity_by_name = hashmap_new(&string_hash_ops_free);
+ if (!batteries_capacity_by_name)
+ return log_oom_debug();
+
+ r = battery_enumerator_new(&e);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+ FOREACH_DEVICE(e, dev) {
+ _cleanup_free_ char *battery_name_copy = NULL;
+ const char *battery_name;
+ int battery_capacity;
+
+ battery_capacity = r = read_battery_capacity_percentage(dev);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to get battery capacity, ignoring: %m");
+ continue;
+ }
+
+ r = sd_device_get_property_value(dev, "POWER_SUPPLY_NAME", &battery_name);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to read battery name, ignoring: %m");
+ continue;
+ }
+
+ battery_name_copy = strdup(battery_name);
+ if (!battery_name_copy)
+ return log_oom_debug();
+
+ r = hashmap_put(batteries_capacity_by_name, battery_name_copy, CAPACITY_TO_PTR(battery_capacity));
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to store battery capacity: %m");
+
+ TAKE_PTR(battery_name_copy);
+ }
+
+ *ret = TAKE_PTR(batteries_capacity_by_name);
+
+ return 0;
+}
+
+/* Read file path and return hash of value in that file */
+static int get_battery_identifier(sd_device *dev, const char *property, struct siphash *state) {
+ const char *x;
+ int r;
+
+ assert(dev);
+ assert(property);
+ assert(state);
+
+ r = sd_device_get_property_value(dev, property, &x);
if (r == -ENOENT)
- log_debug_errno(r, "%s is unavailable: %m", filepath);
+ log_device_debug_errno(dev, r, "battery device property %s is unavailable, ignoring: %m", property);
else if (r < 0)
- return log_debug_errno(r, "Failed to read %s: %m", filepath);
- else if (isempty(value))
- log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "%s is empty: %m", filepath);
+ return log_device_debug_errno(dev, r, "Failed to read battery device property %s: %m", property);
+ else if (isempty(x))
+ log_device_debug(dev, "battery device property '%s' is null.", property);
else
- siphash24_compress_string(value, ret);
+ siphash24_compress_string(x, state);
return 0;
}
/* Read system and battery identifier from specific location and generate hash of it */
-static int get_system_battery_identifier_hash(uint64_t *ret_hash) {
+static int get_system_battery_identifier_hash(sd_device *dev, uint64_t *ret) {
struct siphash state;
sd_id128_t machine_id, product_id;
int r;
- assert(ret_hash);
+ assert(ret);
+ assert(dev);
siphash24_init(&state, BATTERY_DISCHARGE_RATE_HASH_KEY.bytes);
- get_battery_identifier("/sys/class/power_supply/BAT0/manufacturer", &state);
- get_battery_identifier("/sys/class/power_supply/BAT0/model_name", &state);
- get_battery_identifier("/sys/class/power_supply/BAT0/serial_number", &state);
+
+ get_battery_identifier(dev, "POWER_SUPPLY_MANUFACTURER", &state);
+ get_battery_identifier(dev, "POWER_SUPPLY_MODEL_NAME", &state);
+ get_battery_identifier(dev, "POWER_SUPPLY_SERIAL_NUMBER", &state);
r = sd_id128_get_machine(&machine_id);
if (r == -ENOENT)
else
siphash24_compress(&product_id, sizeof(sd_id128_t), &state);
- *ret_hash = siphash24_finalize(&state);
+ *ret = siphash24_finalize(&state);
return 0;
}
/* Battery percentage discharge rate per hour is read from specific file. It is stored along with system
* and battery identifier hash to maintain the integrity of discharge rate value */
-int get_battery_discharge_rate(void) {
- _cleanup_free_ char *hash_id_discharge_rate = NULL, *stored_hash_id = NULL, *stored_discharge_rate = NULL;
+static int get_battery_discharge_rate(sd_device *dev, int *ret) {
+ _cleanup_fclose_ FILE *f = NULL;
+ uint64_t current_hash_id;
const char *p;
- uint64_t current_hash_id, hash_id;
- int discharge_rate, r;
+ int r;
- r = read_one_line_file(DISCHARGE_RATE_FILEPATH, &hash_id_discharge_rate);
- if (r < 0)
- return log_debug_errno(r, "Failed to read discharge rate from %s: %m", DISCHARGE_RATE_FILEPATH);
+ assert(dev);
+ assert(ret);
- p = hash_id_discharge_rate;
- r = extract_many_words(&p, " ", 0, &stored_hash_id, &stored_discharge_rate, NULL);
- if (r < 0)
- return log_debug_errno(r, "Failed to parse hash_id and discharge_rate read from %s location: %m", DISCHARGE_RATE_FILEPATH);
- if (r != 2)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid number of items fetched from %s", DISCHARGE_RATE_FILEPATH);
+ f = fopen(DISCHARGE_RATE_FILEPATH, "re");
+ if (!f)
+ return log_debug_errno(errno, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH ": %m");
- r = safe_atou64(stored_hash_id, &hash_id);
+ r = get_system_battery_identifier_hash(dev, ¤t_hash_id);
if (r < 0)
- return log_debug_errno(r, "Failed to parse discharge rate read from %s location: %m", DISCHARGE_RATE_FILEPATH);
+ return log_device_debug_errno(dev, r, "Failed to generate system battery identifier hash: %m");
- r = get_system_battery_identifier_hash(¤t_hash_id);
- if (r < 0)
- return log_debug_errno(r, "Failed to generate system battery identifier hash: %m");
+ for (;;) {
+ _cleanup_free_ char *stored_hash_id = NULL, *stored_discharge_rate = NULL, *line = NULL;
+ uint64_t hash_id;
+ int discharge_rate;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH ": %m");
+ if (r == 0)
+ break;
- if(current_hash_id != hash_id)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Current identifier does not match stored identifier: %m");
+ p = line;
+ r = extract_many_words(&p, NULL, 0, &stored_hash_id, &stored_discharge_rate, NULL);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse hash_id and discharge_rate read from " DISCHARGE_RATE_FILEPATH ": %m");
+ if (r != 2)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid number of items fetched from " DISCHARGE_RATE_FILEPATH);
- r = safe_atoi(stored_discharge_rate, &discharge_rate);
- if (r < 0)
- return log_debug_errno(r, "Failed to parse discharge rate read from %s location: %m", DISCHARGE_RATE_FILEPATH);
+ r = safe_atou64(stored_hash_id, &hash_id);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse hash ID read from " DISCHARGE_RATE_FILEPATH " location: %m");
+
+ if (current_hash_id != hash_id)
+ /* matching device not found, move to next line */
+ continue;
+
+ r = safe_atoi(stored_discharge_rate, &discharge_rate);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to parse discharge rate read from " DISCHARGE_RATE_FILEPATH ": %m");
+
+ if (!battery_discharge_rate_is_valid(discharge_rate))
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid battery discharge percentage rate per hour: %m");
- if (!battery_discharge_rate_is_valid(discharge_rate))
- return log_debug_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid battery discharge percentage rate per hour: %m");
+ *ret = discharge_rate;
+ return 0; /* matching device found, exit iteration */
+ }
- return discharge_rate;
+ return -ENOENT;
}
/* Write battery percentage discharge rate per hour along with system and battery identifier hash to file */
-int put_battery_discharge_rate(int estimated_battery_discharge_rate) {
- uint64_t system_hash_id;
+static int put_battery_discharge_rate(int estimated_battery_discharge_rate, uint64_t system_hash_id, bool trunc) {
int r;
if (!battery_discharge_rate_is_valid(estimated_battery_discharge_rate))
- return log_debug_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid battery discharge percentage rate per hour: %m");
+ return log_debug_errno(SYNTHETIC_ERRNO(ERANGE),
+ "Invalid battery discharge rate %d%% per hour: %m",
+ estimated_battery_discharge_rate);
- r = get_system_battery_identifier_hash(&system_hash_id);
+ r = write_string_filef(
+ DISCHARGE_RATE_FILEPATH,
+ WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_MKDIR_0755 | (trunc ? WRITE_STRING_FILE_TRUNCATE : 0),
+ "%"PRIu64" %d",
+ system_hash_id,
+ estimated_battery_discharge_rate);
if (r < 0)
- return log_debug_errno(r, "Failed to generate system battery identifier hash: %m");
+ return log_debug_errno(r, "Failed to update %s: %m", DISCHARGE_RATE_FILEPATH);
- r = write_string_filef(
- DISCHARGE_RATE_FILEPATH,
- WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755,
- "%"PRIu64" %d",
- system_hash_id,
- estimated_battery_discharge_rate);
+ log_debug("Estimated discharge rate %d%% per hour successfully saved to %s", estimated_battery_discharge_rate, DISCHARGE_RATE_FILEPATH);
+
+ return 0;
+}
+
+/* Estimate battery discharge rate using stored previous and current capacity over timestamp difference */
+int estimate_battery_discharge_rate_per_hour(
+ Hashmap *last_capacity,
+ Hashmap *current_capacity,
+ usec_t before_timestamp,
+ usec_t after_timestamp) {
+
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
+ bool trunc = true;
+ int r;
+
+ assert(last_capacity);
+ assert(current_capacity);
+ assert(before_timestamp < after_timestamp);
+
+ r = battery_enumerator_new(&e);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+ FOREACH_DEVICE(e, dev) {
+ int battery_last_capacity, battery_current_capacity, battery_discharge_rate;
+ const char *battery_name;
+ uint64_t system_hash_id;
+
+ r = sd_device_get_property_value(dev, "POWER_SUPPLY_NAME", &battery_name);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to read battery name, ignoring: %m");
+ continue;
+ }
+
+ battery_last_capacity = get_capacity_by_name(last_capacity, battery_name);
+ if (battery_last_capacity < 0)
+ continue;
+
+ battery_current_capacity = get_capacity_by_name(current_capacity, battery_name);
+ if (battery_current_capacity < 0)
+ continue;
+
+ if (battery_current_capacity >= battery_last_capacity) {
+ log_device_debug(dev, "Battery was not discharged during suspension");
+ continue;
+ }
+
+ r = get_system_battery_identifier_hash(dev, &system_hash_id);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to generate system battery identifier hash: %m");
+
+ log_device_debug(dev,
+ "%d%% was discharged in %s. Estimating discharge rate...",
+ battery_last_capacity - battery_current_capacity,
+ FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_SEC));
+
+ battery_discharge_rate = (battery_last_capacity - battery_current_capacity) * USEC_PER_HOUR / (after_timestamp - before_timestamp);
+ r = put_battery_discharge_rate(battery_discharge_rate, system_hash_id, trunc);
+ if (r < 0)
+ log_device_warning_errno(dev, r, "Failed to update battery discharge rate, ignoring: %m");
+ else
+ trunc = false;
+ }
+
+ return 0;
+}
+
+/* calculate the suspend interval for each battery and then return the sum of it */
+int get_total_suspend_interval(Hashmap *last_capacity, usec_t *ret) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ usec_t total_suspend_interval = 0;
+ sd_device *dev;
+ int r;
+
+ assert(last_capacity);
+ assert(ret);
+
+ r = battery_enumerator_new(&e);
if (r < 0)
- return log_debug_errno(r, "Failed to create %s: %m", DISCHARGE_RATE_FILEPATH);
+ return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+ FOREACH_DEVICE(e, dev) {
+ int battery_last_capacity, previous_discharge_rate = 0;
+ const char *battery_name;
+ usec_t suspend_interval;
+
+ r = sd_device_get_property_value(dev, "POWER_SUPPLY_NAME", &battery_name);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to read battery name, ignoring: %m");
+ continue;
+ }
+
+ battery_last_capacity = PTR_TO_CAPACITY(hashmap_get(last_capacity, battery_name));
+ if (battery_last_capacity <= 0)
+ continue;
+
+ r = get_battery_discharge_rate(dev, &previous_discharge_rate);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Failed to get discharge rate, ignoring: %m");
+ continue;
+ }
+
+ if (previous_discharge_rate == 0)
+ continue;
+
+ if (battery_last_capacity * 2 <= previous_discharge_rate) {
+ log_device_debug(dev, "Current battery capacity percentage too low compared to discharge rate");
+ continue;
+ }
+ suspend_interval = battery_last_capacity * USEC_PER_HOUR / previous_discharge_rate;
+
+ total_suspend_interval = usec_add(total_suspend_interval, suspend_interval);
+ }
+ /* The previous discharge rate is stored in per hour basis so converted to minutes.
+ * Subtracted 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
+ total_suspend_interval = usec_sub_unsigned(total_suspend_interval, 30 * USEC_PER_MINUTE);
+ if (total_suspend_interval == 0)
+ return -ENOENT;
+
+ *ret = total_suspend_interval;
- log_debug("Estimated discharge rate %d successfully updated to %s", estimated_battery_discharge_rate, DISCHARGE_RATE_FILEPATH);
return 0;
}
#pragma once
#include <linux/fiemap.h>
+
+#include "hashmap.h"
#include "time-util.h"
typedef enum SleepOperation {
int can_sleep(SleepOperation operation);
int can_sleep_disk(char **types);
int can_sleep_state(char **types);
-int read_battery_capacity_percentage(void);
int battery_is_low(void);
-int get_battery_discharge_rate(void);
-int put_battery_discharge_rate(int estimated_battery_discharge_rate);
+int get_total_suspend_interval(Hashmap *last_capacity, usec_t *ret);
+int fetch_batteries_capacity_by_name(Hashmap **ret_current_capacity);
+int estimate_battery_discharge_rate_per_hour(
+ Hashmap *last_capacity,
+ Hashmap *current_capacity,
+ usec_t before_timestamp,
+ usec_t after_timestamp);
const char* sleep_operation_to_string(SleepOperation s) _const_;
SleepOperation sleep_operation_from_string(const char *s) _pure_;
return 0;
}
+#define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited"
+
static int tpm2_credit_random(ESYS_CONTEXT *c) {
size_t rps, done = 0;
TSS2_RC rc;
+ usec_t t;
int r;
assert(c);
* but likely better. Note that we don't trust the TPM RNG very much, hence do not actually credit
* any entropy. */
+ if (access(TPM2_CREDIT_RANDOM_FLAG_PATH, F_OK) < 0) {
+ if (errno != ENOENT)
+ log_debug_errno(errno, "Failed to detect if '" TPM2_CREDIT_RANDOM_FLAG_PATH "' exists, ignoring: %m");
+ } else {
+ log_debug("Not adding TPM2 entropy to the kernel random pool again.");
+ return 0; /* Already done */
+ }
+
+ t = now(CLOCK_MONOTONIC);
+
for (rps = random_pool_size(); rps > 0;) {
_cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL;
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Zero-sized entropy returned from TPM.");
- r = random_write_entropy(-1, buffer->buffer, buffer->size, false);
+ r = random_write_entropy(-1, buffer->buffer, buffer->size, /* credit= */ false);
if (r < 0)
return log_error_errno(r, "Failed wo write entropy to kernel: %m");
rps = LESS_BY(rps, buffer->size);
}
- log_debug("Added %zu bytes of entropy to the kernel random pool.", done);
+ log_debug("Added %zu bytes of TPM2 entropy to the kernel random pool in %s.", done, FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - t, 0));
+
+ r = touch(TPM2_CREDIT_RANDOM_FLAG_PATH);
+ if (r < 0)
+ log_debug_errno(r, "Failed to touch '" TPM2_CREDIT_RANDOM_FLAG_PATH "', ignoring: %m");
+
return 0;
}
.type = TPM2_ALG_ECC,
.nameAlg = TPM2_ALG_SHA256,
.objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
- .parameters = {
- .eccDetail = {
- .symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- },
- .scheme.scheme = TPM2_ALG_NULL,
- .curveID = TPM2_ECC_NIST_P256,
- .kdf.scheme = TPM2_ALG_NULL,
+ .parameters.eccDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
},
+ .scheme.scheme = TPM2_ALG_NULL,
+ .curveID = TPM2_ECC_NIST_P256,
+ .kdf.scheme = TPM2_ALG_NULL,
},
},
};
.type = TPM2_ALG_RSA,
.nameAlg = TPM2_ALG_SHA256,
.objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
- .parameters = {
- .rsaDetail = {
- .symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- },
- .scheme.scheme = TPM2_ALG_NULL,
- .keyBits = 2048,
+ .parameters.rsaDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
},
+ .scheme.scheme = TPM2_ALG_NULL,
+ .keyBits = 2048,
},
},
};
return 0;
}
-static void tpm2_pcr_mask_to_selecion(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret) {
+static void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret) {
assert(ret);
/* We only do 24bit here, as that's what PC TPMs are supposed to support */
*ret = (TPML_PCR_SELECTION) {
.count = 1,
- .pcrSelections[0].hash = bank,
- .pcrSelections[0].sizeofSelect = 3,
- .pcrSelections[0].pcrSelect[0] = mask & 0xFF,
- .pcrSelections[0].pcrSelect[1] = (mask >> 8) & 0xFF,
- .pcrSelections[0].pcrSelect[2] = (mask >> 16) & 0xFF,
+ .pcrSelections[0] = {
+ .hash = bank,
+ .sizeofSelect = 3,
+ .pcrSelect[0] = mask & 0xFF,
+ .pcrSelect[1] = (mask >> 8) & 0xFF,
+ .pcrSelect[2] = (mask >> 16) & 0xFF,
+ }
};
}
* actually measure into them, or only into a suboptimal bank. If so, the PCRs should be all zero or
* all 0xFF. Detect that, so that we can warn and maybe pick a better bank. */
- tpm2_pcr_mask_to_selecion(mask, bank, &selection);
+ tpm2_pcr_mask_to_selection(mask, bank, &selection);
rc = sym_Esys_PCR_Read(
c,
static int tpm2_make_encryption_session(
ESYS_CONTEXT *c,
- ESYS_TR tpmKey,
+ ESYS_TR primary,
ESYS_TR *ret_session) {
static const TPMT_SYM_DEF symmetric = {
.algorithm = TPM2_ALG_AES,
- .keyBits = {
- .aes = 128,
- },
- .mode = {
- .aes = TPM2_ALG_CFB,
- },
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
};
const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT |
TPMA_SESSION_CONTINUESESSION;
* recover the salt, which is then used for key derivation. */
rc = sym_Esys_StartAuthSession(
c,
- tpmKey,
+ primary,
ESYS_TR_NONE,
ESYS_TR_NONE,
ESYS_TR_NONE,
static int tpm2_make_pcr_session(
ESYS_CONTEXT *c,
- ESYS_TR tpmKey,
+ ESYS_TR primary,
ESYS_TR parent_session,
+ TPM2_SE session_type,
uint32_t pcr_mask,
uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
bool use_pin,
static const TPMT_SYM_DEF symmetric = {
.algorithm = TPM2_ALG_AES,
- .keyBits = {
- .aes = 128
- },
- .mode = {
- .aes = TPM2_ALG_CFB,
- }
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
};
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
TPML_PCR_SELECTION pcr_selection;
if (r == 0)
log_notice("Selected TPM2 PCRs are not initialized on this system, most likely due to a firmware issue. PCR policy is effectively not enforced. Proceeding anyway.");
- tpm2_pcr_mask_to_selecion(pcr_mask, pcr_bank, &pcr_selection);
+ tpm2_pcr_mask_to_selection(pcr_mask, pcr_bank, &pcr_selection);
} else {
TPMI_ALG_HASH h;
if (r < 0)
return r;
- tpm2_pcr_mask_to_selecion(pcr_mask, h, &pcr_selection);
+ tpm2_pcr_mask_to_selection(pcr_mask, h, &pcr_selection);
}
rc = sym_Esys_StartAuthSession(
c,
- tpmKey,
+ primary,
ESYS_TR_NONE,
parent_session,
ESYS_TR_NONE,
ESYS_TR_NONE,
NULL,
- TPM2_SE_POLICY,
+ session_type,
&symmetric,
TPM2_ALG_SHA256,
&session);
if (r < 0)
goto finish;
- r = tpm2_make_pcr_session(c.esys_context, primary, session, pcr_mask, UINT16_MAX, !!pin, NULL,
- &policy_digest, &pcr_bank);
+ r = tpm2_make_pcr_session(
+ c.esys_context,
+ primary,
+ session,
+ TPM2_SE_TRIAL,
+ pcr_mask,
+ /* pcr_bank= */ UINT16_MAX,
+ !!pin,
+ /* ret_session= */ NULL,
+ &policy_digest,
+ &pcr_bank);
if (r < 0)
goto finish;
.type = TPM2_ALG_KEYEDHASH,
.nameAlg = TPM2_ALG_SHA256,
.objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
- .parameters = {
- .keyedHashDetail = {
- .scheme.scheme = TPM2_ALG_NULL,
- },
- },
- .unique = {
- .keyedHash = {
- .size = 32,
- },
- },
+ .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
+ .unique.keyedHash.size = 32,
.authPolicy = *policy_digest,
},
};
if (r < 0)
goto finish;
- r = tpm2_make_pcr_session(c.esys_context, primary, hmac_session, pcr_mask, pcr_bank, !!pin, &session,
- &policy_digest, NULL);
+ r = tpm2_make_pcr_session(
+ c.esys_context,
+ primary,
+ hmac_session,
+ TPM2_SE_POLICY,
+ pcr_mask,
+ pcr_bank,
+ !!pin,
+ &session,
+ &policy_digest,
+ /* ret_pcr_bank= */ NULL);
if (r < 0)
goto finish;
static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = {
[RESOLVE_NAME_NEVER] = "never",
- [RESOLVE_NAME_LATE] = "late",
+ [RESOLVE_NAME_LATE] = "late",
[RESOLVE_NAME_EARLY] = "early",
};
int on_ac_power(void) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
- bool found_offline = false, found_online = false;
+ bool found_offline = false, found_online = false, found_battery = false;
sd_device *d;
int r;
* for defined power source types. Also see:
* https://docs.kernel.org/admin-guide/abi-testing.html#abi-file-testing-sysfs-class-power */
if (streq(val, "Battery")) {
+ found_battery = true;
log_device_debug(d, "The power supply is battery, ignoring.");
continue;
}
log_debug("Found at least one online non-battery power supply, system is running on AC power.");
else if (!found_offline)
log_debug("Found no offline non-battery power supply, assuming system is running on AC power.");
+ else if (!found_battery)
+ log_debug("Found no battery, assuming system is running on AC power.");
else
log_debug("All non-battery power supplies are offline, assuming system is running with battery.");
- return found_online || !found_offline;
+ return found_online || !found_offline || !found_battery;
}
bool udev_available(void) {
if (hr->memory_max != UINT64_MAX)
printf(" Memory Max: %s\n", FORMAT_BYTES(hr->memory_max));
- if (hr->cpu_weight != UINT64_MAX)
+ if (hr->cpu_weight == CGROUP_WEIGHT_IDLE)
+ printf(" CPU Weight: %s\n", "idle");
+ else if (hr->cpu_weight != UINT64_MAX)
printf(" CPU Weight: %" PRIu64 "\n", hr->cpu_weight);
if (hr->io_weight != UINT64_MAX)
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "def.h"
+#include "errno-util.h"
#include "exec-util.h"
#include "fd-util.h"
#include "fileio.h"
}
int main(int argc, char *argv[]) {
+ static const char* const dirs[] = {
+ SYSTEM_SHUTDOWN_PATH,
+ NULL
+ };
_cleanup_free_ char *cgroup = NULL;
char *arguments[3];
int cmd, r;
- static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
/* The log target defaults to console, but the original systemd process will pass its log target in through a
* command line argument, which will override this default. Also, ensure we'll never log to the journal or
umask(0022);
if (getpid_cached() != 1) {
- log_error("Not executed by init (PID 1).");
- r = -EPERM;
+ r = log_error_errno(SYNTHETIC_ERRNO(EPERM), "Not executed by init (PID 1).");
goto error;
}
else if (streq(arg_verb, "exit"))
cmd = 0; /* ignored, just checking that arg_verb is valid */
else {
- log_error("Unknown action '%s'.", arg_verb);
- r = -EINVAL;
+ r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'.", arg_verb);
goto error;
}
(void) watchdog_ping();
- /* Let's trim the cgroup tree on each iteration so
- that we leave an empty cgroup tree around, so that
- container managers get a nice notify event when we
- are down */
+ /* Let's trim the cgroup tree on each iteration so that we leave an empty cgroup tree around,
+ * so that container managers get a nice notify event when we are down */
if (cgroup)
(void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
continue;
}
- /* If in this iteration we didn't manage to
- * unmount/deactivate anything, we simply give up */
+ /* If in this iteration we didn't manage to unmount/deactivate anything, we simply give up */
if (!changed) {
log_info("Cannot finalize remaining%s%s%s%s%s continuing.",
need_umount ? " file systems," : "",
need_md_detach ? " MD devices," : "");
}
- /* We're done with the watchdog. Note that the watchdog is explicitly not
- * stopped here. It remains active to guard against any issues during the
- * rest of the shutdown sequence. */
+ /* We're done with the watchdog. Note that the watchdog is explicitly not stopped here. It remains
+ * active to guard against any issues during the rest of the shutdown sequence. */
watchdog_free_device();
- arguments[0] = NULL;
+ arguments[0] = NULL; /* Filled in by execute_directories(), when needed */
arguments[1] = arg_verb;
arguments[2] = NULL;
(void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
need_dm_detach ? " DM devices," : "",
need_md_detach ? " MD devices," : "");
- /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
- * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we
- * sync'ed things already once above, but we did some more work since then which might have caused IO, hence
- * let's do it once more. Do not remove this sync, data corruption will result. */
+ /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
+ * to be sync'ed explicitly in advance. So let's do this here, but not needlessly slow down
+ * containers. Note that we sync'ed things already once above, but we did some more work since then
+ * which might have caused IO, hence let's do it once more. Do not remove this sync, data corruption
+ * will result. */
if (!in_container)
sync_with_progress();
/* Child */
execv(args[0], (char * const *) args);
+ log_debug_errno(errno, "Failed to execute '" KEXEC "' binary, proceeding with reboot(RB_KEXEC): %m");
/* execv failed (kexec binary missing?), so try simply reboot(RB_KEXEC) */
(void) reboot(cmd);
}
(void) reboot(cmd);
- if (errno == EPERM && in_container) {
- /* If we are in a container, and we lacked
- * CAP_SYS_BOOT just exit, this will kill our
+ if (ERRNO_IS_PRIVILEGE(errno) && in_container) {
+ /* If we are in a container, and we lacked CAP_SYS_BOOT just exit, this will kill our
* container for good. */
log_info("Exiting container.");
return EXIT_SUCCESS;
}
static int execute_s2h(const SleepConfig *sleep_config) {
+ _cleanup_hashmap_free_ Hashmap *last_capacity = NULL, *current_capacity = NULL;
int r;
assert(sleep_config);
while (battery_is_low() == 0) {
_cleanup_close_ int tfd = -1;
struct itimerspec ts = {};
- usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0;
+ usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0, total_suspend_interval;
bool woken_by_timer;
- int last_capacity = 0, current_capacity = 0, previous_discharge_rate, estimated_discharge_rate = 0;
tfd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK|TFD_CLOEXEC);
if (tfd < 0)
return log_error_errno(errno, "Error creating timerfd: %m");
/* Store current battery capacity and current time before suspension */
- r = read_battery_capacity_percentage();
- if (r >= 0) {
- last_capacity = r;
- log_debug("Current battery charge percentage: %d%%", last_capacity);
+ r = fetch_batteries_capacity_by_name(&last_capacity);
+ if (r >= 0)
before_timestamp = now(CLOCK_BOOTTIME);
- } else if (r == -ENOENT)
+ else if (r == -ENOENT)
/* In case of no battery, system suspend interval will be set to HibernateDelaySec=. */
log_debug_errno(r, "Suspend Interval value set to %s: %m", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC));
else
return log_error_errno(r, "Error fetching battery capacity percentage: %m");
- r = get_battery_discharge_rate();
+ r = get_total_suspend_interval(last_capacity, &total_suspend_interval);
if (r < 0)
- log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to get discharge rate, ignoring: %m");
- else if (last_capacity * 2 <= r) {
- /* System should hibernate in case discharge rate is higher than double of battery current capacity
- * why double : Because while calculating suspend interval, we have taken a buffer of 30 minute and
- * discharge_rate is calculated on per 60 minute basis which is double. Also suspend_interval > 0 */
- log_debug("Current battery percentage capacity too low to suspend, so invoking hibernation");
- break;
- } else {
- previous_discharge_rate = r;
- assert(previous_discharge_rate != 0);
- suspend_interval = usec_sub_unsigned(last_capacity * USEC_PER_HOUR / previous_discharge_rate, 30 * USEC_PER_MINUTE);
- /* The previous discharge rate is stored in per hour basis so converted to minutes.
- * Subtracted 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
- }
+ log_debug_errno(r, "Failed to estimate suspend interval using previous discharge rate, ignoring: %m");
+ else
+ suspend_interval = total_suspend_interval;
+
log_debug("Set timerfd wake alarm for %s", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC));
/* Wake alarm for system with or without battery to hibernate or estimate discharge rate whichever is applicable */
timespec_store(&ts.it_value, suspend_interval);
/* Store fd_wait status */
woken_by_timer = FLAGS_SET(r, POLLIN);
- r = read_battery_capacity_percentage();
- if (r >= 0) {
- current_capacity = r;
- log_debug("Current battery charge percentage after wakeup: %d%%", current_capacity);
- } else if (r == -ENOENT) {
- /* In case of no battery, system will be hibernated after 1st cycle of suspend */
+ r = fetch_batteries_capacity_by_name(¤t_capacity);
+ if (r < 0) {
+ /* In case of no battery or error while getting charge level, no need to measure
+ * discharge rate. Instead system should wakeup if it is manual wakeup or
+ * hibernate if this is a timer wakeup. */
log_debug_errno(r, "Battery capacity percentage unavailable, cannot estimate discharge rate: %m");
+ if (!woken_by_timer)
+ return 0;
break;
- } else
- return log_error_errno(r, "Error fetching battery capacity percentage: %m");
+ }
- if (current_capacity >= last_capacity)
- log_debug("Battery was not discharged during suspension");
- else {
- after_timestamp = now(CLOCK_BOOTTIME);
- log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR));
+ after_timestamp = now(CLOCK_BOOTTIME);
+ log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR));
- estimated_discharge_rate = (last_capacity - current_capacity) * USEC_PER_HOUR / (after_timestamp - before_timestamp);
- r = put_battery_discharge_rate(estimated_discharge_rate);
+ if (after_timestamp != before_timestamp) {
+ r = estimate_battery_discharge_rate_per_hour(last_capacity, current_capacity, before_timestamp, after_timestamp);
if (r < 0)
- log_warning_errno(r, "Failed to update battery discharge rate, ignoring: %m");
- }
+ log_warning_errno(r, "Failed to estimate and update battery discharge rate, ignoring: %m");
+ } else
+ log_debug("System woke up too early to estimate discharge rate");
if (!woken_by_timer)
/* Return as manual wakeup done. This also will return in case battery was charged during suspension */
#include "sd-bus.h"
+#include "bus-locator.h"
#include "bus-util.h"
#include "bus-error.h"
#include "def.h"
log_info("Reloading system manager configuration");
- r = sd_bus_message_new_method_call(
+ r = bus_message_new_method_call(
bus,
&m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"Reload");
if (r < 0)
return bus_log_create_error(r);
- /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
- * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
- * their timeout, and for everything else there's the same time budget in place. */
-
- r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+ /* Reloading the daemon may take long, hence set a longer timeout here */
+ r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
if (r < 0)
return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
log_info("Starting "SPECIAL_DEFAULT_TARGET);
/* Start this unit only if we can replace basic.target with it */
- r = sd_bus_call_method(bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartUnit",
- &error,
- NULL,
- "ss", SPECIAL_DEFAULT_TARGET, "isolate");
+ r = bus_call_method(
+ bus,
+ bus_systemd_mgr,
+ "StartUnit",
+ &error,
+ NULL,
+ "ss", SPECIAL_DEFAULT_TARGET, "isolate");
if (r < 0)
return log_error_errno(r, "Failed to start "SPECIAL_DEFAULT_TARGET": %s", bus_error_message(&error, r));
if (strv_isempty(arg_prefixes))
return true;
- STRV_FOREACH(i, arg_prefixes) {
- const char *t;
-
- t = path_startswith(*i, "/proc/sys/");
- if (!t)
- t = *i;
-
- if (path_startswith(p, t))
- return true;
- }
-
- return false;
+ return path_startswith_strv(p, arg_prefixes);
}
static Option *option_new(
return TAKE_PTR(o);
}
-static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_failure) {
+static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_failure, bool ignore_enoent) {
int r;
r = sysctl_write(key, value);
* In all other cases log an error and make the tool fail. */
if (ignore_failure || (!arg_strict && (r == -EROFS || ERRNO_IS_PRIVILEGE(r))))
log_debug_errno(r, "Couldn't write '%s' to '%s', ignoring: %m", value, key);
- else if (!arg_strict && r == -ENOENT)
+ else if (ignore_enoent && r == -ENOENT)
log_warning_errno(r, "Couldn't write '%s' to '%s', ignoring: %m", value, key);
else
return log_error_errno(r, "Couldn't write '%s' to '%s': %m", value, key);
return 0;
}
-static int apply_all(OrderedHashmap *sysctl_options) {
- Option *option;
- int r = 0;
+static int apply_glob_option_with_prefix(OrderedHashmap *sysctl_options, Option *option, const char *prefix) {
+ _cleanup_strv_free_ char **paths = NULL;
+ _cleanup_free_ char *pattern = NULL;
+ int r, k;
- ORDERED_HASHMAP_FOREACH(option, sysctl_options) {
- int k;
+ assert(sysctl_options);
+ assert(option);
- /* Ignore "negative match" options, they are there only to exclude stuff from globs. */
- if (!option->value)
+ if (prefix) {
+ _cleanup_free_ char *key = NULL;
+
+ r = path_glob_can_match(option->key, prefix, &key);
+ if (r < 0)
+ return log_error_errno(r, "Failed to check if the glob '%s' matches prefix '%s': %m",
+ option->key, prefix);
+ if (r == 0) {
+ log_debug("The glob '%s' does not match prefix '%s'.", option->key, prefix);
+ return 0;
+ }
+
+ log_debug("The glob '%s' is prefixed with '%s': '%s'", option->key, prefix, key);
+
+ if (!string_is_glob(key)) {
+ /* The prefixed pattern is not glob anymore. Let's skip to call glob(). */
+ if (ordered_hashmap_contains(sysctl_options, key)) {
+ log_debug("Not setting %s (explicit setting exists).", key);
+ return 0;
+ }
+
+ return sysctl_write_or_warn(key, option->value,
+ /* ignore_failure = */ option->ignore_failure,
+ /* ignore_enoent = */ true);
+ }
+
+ pattern = path_join("/proc/sys", key);
+ } else
+ pattern = path_join("/proc/sys", option->key);
+ if (!pattern)
+ return log_oom();
+
+ r = glob_extend(&paths, pattern, GLOB_NOCHECK);
+ if (r < 0) {
+ if (r == -ENOENT) {
+ log_debug("No match for glob: %s", option->key);
+ return 0;
+ }
+ if (option->ignore_failure || ERRNO_IS_PRIVILEGE(r)) {
+ log_debug_errno(r, "Failed to resolve glob '%s', ignoring: %m", option->key);
+ return 0;
+ } else
+ return log_error_errno(r, "Couldn't resolve glob '%s': %m", option->key);
+ }
+
+ STRV_FOREACH(s, paths) {
+ const char *key;
+
+ assert_se(key = path_startswith(*s, "/proc/sys"));
+
+ if (ordered_hashmap_contains(sysctl_options, key)) {
+ log_debug("Not setting %s (explicit setting exists).", key);
continue;
+ }
- if (string_is_glob(option->key)) {
- _cleanup_strv_free_ char **paths = NULL;
- _cleanup_free_ char *pattern = NULL;
+ k = sysctl_write_or_warn(key, option->value,
+ /* ignore_failure = */ option->ignore_failure,
+ /* ignore_enoent = */ !arg_strict);
+ if (k < 0 && r >= 0)
+ r = k;
+ }
- pattern = path_join("/proc/sys", option->key);
- if (!pattern)
- return log_oom();
+ return r;
+}
- k = glob_extend(&paths, pattern, GLOB_NOCHECK);
- if (k < 0) {
- if (option->ignore_failure || ERRNO_IS_PRIVILEGE(k))
- log_debug_errno(k, "Failed to resolve glob '%s', ignoring: %m",
- option->key);
- else {
- log_error_errno(k, "Couldn't resolve glob '%s': %m",
- option->key);
- if (r == 0)
- r = k;
- }
+static int apply_glob_option(OrderedHashmap *sysctl_options, Option *option) {
+ int r = 0, k;
- } else if (strv_isempty(paths))
- log_debug("No match for glob: %s", option->key);
+ if (strv_isempty(arg_prefixes))
+ return apply_glob_option_with_prefix(sysctl_options, option, NULL);
- STRV_FOREACH(s, paths) {
- const char *key;
+ STRV_FOREACH(i, arg_prefixes) {
+ k = apply_glob_option_with_prefix(sysctl_options, option, *i);
+ if (k < 0 && r >= 0)
+ r = k;
+ }
- assert_se(key = path_startswith(*s, "/proc/sys"));
+ return r;
+}
- if (!test_prefix(key))
- continue;
+static int apply_all(OrderedHashmap *sysctl_options) {
+ Option *option;
+ int r = 0;
- if (ordered_hashmap_contains(sysctl_options, key)) {
- log_debug("Not setting %s (explicit setting exists).", key);
- continue;
- }
+ ORDERED_HASHMAP_FOREACH(option, sysctl_options) {
+ int k;
- k = sysctl_write_or_warn(key, option->value, option->ignore_failure);
- if (r == 0)
- r = k;
- }
+ /* Ignore "negative match" options, they are there only to exclude stuff from globs. */
+ if (!option->value)
+ continue;
- } else {
- k = sysctl_write_or_warn(option->key, option->value, option->ignore_failure);
- if (r == 0)
- r = k;
- }
+ if (string_is_glob(option->key))
+ k = apply_glob_option(sysctl_options, option);
+ else
+ k = sysctl_write_or_warn(option->key, option->value,
+ /* ignore_failure = */ option->ignore_failure,
+ /* ignore_enoent = */ !arg_strict);
+ if (k < 0 && r >= 0)
+ r = k;
}
return r;
!test_prefix(p))
continue;
- if (ordered_hashmap_ensure_allocated(sysctl_options, &option_hash_ops) < 0)
- return log_oom();
-
existing = ordered_hashmap_get(*sysctl_options, p);
if (existing) {
if (streq_ptr(value, existing->value)) {
if (!new_option)
return log_oom();
- k = ordered_hashmap_put(*sysctl_options, new_option->key, new_option);
+ k = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, new_option->key, new_option);
if (k < 0)
return log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", p);
break;
case ARG_PREFIX: {
+ const char *s;
char *p;
/* We used to require people to specify absolute paths
* sysctl name available. */
sysctl_normalize(optarg);
- if (path_startswith(optarg, "/proc/sys"))
- p = strdup(optarg);
- else
- p = path_join("/proc/sys", optarg);
+ s = path_startswith(optarg, "/proc/sys");
+ p = strdup(s ?: optarg);
if (!p)
return log_oom();
if (r < 0)
return bus_log_create_error(r);
- /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are
- * rerun which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the
- * generators can have their timeout, and for everything else there's the same time budget in
- * place. */
-
- r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+ /* Reloading the daemon may take long, hence set a longer timeout here */
+ r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
/* On reexecution, we expect a disconnect, not a reply */
if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && action == ACTION_REEXEC)
int sd_device_monitor_detach_event(sd_device_monitor *m);
sd_event *sd_device_monitor_get_event(sd_device_monitor *m);
sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *m);
+int sd_device_monitor_set_description(sd_device_monitor *m, const char *description);
+int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret);
int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata);
int sd_device_monitor_stop(sd_device_monitor *m);
int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret);
int sd_dhcp_client_set_mac(
sd_dhcp_client *client,
- const uint8_t *addr,
+ const uint8_t *hw_addr,
const uint8_t *bcast_addr,
size_t addr_len,
uint16_t arp_type);
/* Hey! If you add a new message here, you *must* also update the message catalog with an appropriate explanation */
-/* And if you add a new ID here, make sure to generate a random one with "systemd-id128 new". Do not use any other IDs,
- * and do not count them up manually. */
-
-#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
-#define SD_MESSAGE_JOURNAL_START_STR SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
-#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
-#define SD_MESSAGE_JOURNAL_STOP_STR SD_ID128_MAKE_STR(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
-#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
-#define SD_MESSAGE_JOURNAL_DROPPED_STR SD_ID128_MAKE_STR(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
-#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
-#define SD_MESSAGE_JOURNAL_MISSED_STR SD_ID128_MAKE_STR(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
-#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
-#define SD_MESSAGE_JOURNAL_USAGE_STR SD_ID128_MAKE_STR(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
-
-#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
-#define SD_MESSAGE_COREDUMP_STR SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
-#define SD_MESSAGE_TRUNCATED_CORE SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
-#define SD_MESSAGE_TRUNCATED_CORE_STR SD_ID128_MAKE_STR(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
-#define SD_MESSAGE_BACKTRACE SD_ID128_MAKE(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
-#define SD_MESSAGE_BACKTRACE_STR SD_ID128_MAKE_STR(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
-
-#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
-#define SD_MESSAGE_SESSION_START_STR SD_ID128_MAKE_STR(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
-#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
-#define SD_MESSAGE_SESSION_STOP_STR SD_ID128_MAKE_STR(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
-#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
-#define SD_MESSAGE_SEAT_START_STR SD_ID128_MAKE_STR(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
-#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
-#define SD_MESSAGE_SEAT_STOP_STR SD_ID128_MAKE_STR(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
-#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
-#define SD_MESSAGE_MACHINE_START_STR SD_ID128_MAKE_STR(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
-#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
-#define SD_MESSAGE_MACHINE_STOP_STR SD_ID128_MAKE_STR(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
-
-#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
-#define SD_MESSAGE_TIME_CHANGE_STR SD_ID128_MAKE_STR(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
-#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
-#define SD_MESSAGE_TIMEZONE_CHANGE_STR SD_ID128_MAKE_STR(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
-
-#define SD_MESSAGE_TAINTED SD_ID128_MAKE(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
-#define SD_MESSAGE_TAINTED_STR SD_ID128_MAKE_STR(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
-#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
-#define SD_MESSAGE_STARTUP_FINISHED_STR SD_ID128_MAKE_STR(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
-#define SD_MESSAGE_USER_STARTUP_FINISHED \
- SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
-#define SD_MESSAGE_USER_STARTUP_FINISHED_STR \
- SD_ID128_MAKE_STR(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
-
-#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
-#define SD_MESSAGE_SLEEP_START_STR SD_ID128_MAKE_STR(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
-#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
-#define SD_MESSAGE_SLEEP_STOP_STR SD_ID128_MAKE_STR(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
-
-#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
-#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
-
-#define SD_MESSAGE_FACTORY_RESET SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
-#define SD_MESSAGE_FACTORY_RESET_STR SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
-
-/* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover
- * SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with
- * SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
-#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
-#define SD_MESSAGE_UNIT_STARTING_STR SD_ID128_MAKE_STR(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
-#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
-#define SD_MESSAGE_UNIT_STARTED_STR SD_ID128_MAKE_STR(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
-#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
-#define SD_MESSAGE_UNIT_FAILED_STR SD_ID128_MAKE_STR(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
-#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
-#define SD_MESSAGE_UNIT_STOPPING_STR SD_ID128_MAKE_STR(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
-#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
-#define SD_MESSAGE_UNIT_STOPPED_STR SD_ID128_MAKE_STR(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
-#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
-#define SD_MESSAGE_UNIT_RELOADING_STR SD_ID128_MAKE_STR(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
-#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
-#define SD_MESSAGE_UNIT_RELOADED_STR SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
-
-#define SD_MESSAGE_UNIT_RESTART_SCHEDULED SD_ID128_MAKE(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
-#define SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR \
- SD_ID128_MAKE_STR(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
-
-#define SD_MESSAGE_UNIT_RESOURCES SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
-#define SD_MESSAGE_UNIT_RESOURCES_STR SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
-
-#define SD_MESSAGE_UNIT_SUCCESS SD_ID128_MAKE(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
-#define SD_MESSAGE_UNIT_SUCCESS_STR SD_ID128_MAKE_STR(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
-#define SD_MESSAGE_UNIT_SKIPPED SD_ID128_MAKE(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
-#define SD_MESSAGE_UNIT_SKIPPED_STR SD_ID128_MAKE_STR(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
-#define SD_MESSAGE_UNIT_FAILURE_RESULT SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
-#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR \
- SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
-
-#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
-#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
-
-#define SD_MESSAGE_UNIT_PROCESS_EXIT SD_ID128_MAKE(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
-#define SD_MESSAGE_UNIT_PROCESS_EXIT_STR SD_ID128_MAKE_STR(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
-
-#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
-#define SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR \
- SD_ID128_MAKE_STR(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
-
-#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
-#define SD_MESSAGE_OVERMOUNTING_STR SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
-
-#define SD_MESSAGE_UNIT_OOMD_KILL SD_ID128_MAKE(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
-#define SD_MESSAGE_UNIT_OOMD_KILL_STR SD_ID128_MAKE_STR(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
-
-#define SD_MESSAGE_UNIT_OUT_OF_MEMORY SD_ID128_MAKE(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
-#define SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR SD_ID128_MAKE_STR(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
-
-#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
-#define SD_MESSAGE_LID_OPENED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
-#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
-#define SD_MESSAGE_LID_CLOSED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
-#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
-#define SD_MESSAGE_SYSTEM_DOCKED_STR SD_ID128_MAKE_STR(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
-#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
-#define SD_MESSAGE_SYSTEM_UNDOCKED_STR SD_ID128_MAKE_STR(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
-#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
-#define SD_MESSAGE_POWER_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
-#define SD_MESSAGE_POWER_KEY_LONG_PRESS SD_ID128_MAKE(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
-#define SD_MESSAGE_POWER_KEY_LONG_PRESS_STR \
- SD_ID128_MAKE_STR(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
-#define SD_MESSAGE_REBOOT_KEY SD_ID128_MAKE(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
-#define SD_MESSAGE_REBOOT_KEY_STR SD_ID128_MAKE_STR(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
-#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS SD_ID128_MAKE(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
-#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS_STR \
- SD_ID128_MAKE_STR(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
-#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
-#define SD_MESSAGE_SUSPEND_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
-#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS SD_ID128_MAKE(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
-#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS_STR \
- SD_ID128_MAKE_STR(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
-#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
-#define SD_MESSAGE_HIBERNATE_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
-#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS \
- SD_ID128_MAKE(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
-#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS_STR \
- SD_ID128_MAKE_STR(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
-
-#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
-#define SD_MESSAGE_INVALID_CONFIGURATION_STR \
- SD_ID128_MAKE_STR(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
-
-#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
-#define SD_MESSAGE_DNSSEC_FAILURE_STR SD_ID128_MAKE_STR(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
-#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED \
- SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
-#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR \
- SD_ID128_MAKE_STR(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
-#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
-#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
-
-#define SD_MESSAGE_UNSAFE_USER_NAME SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
-#define SD_MESSAGE_UNSAFE_USER_NAME_STR SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
-
-#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE \
- SD_ID128_MAKE(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
-#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE_STR \
- SD_ID128_MAKE_STR(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
-#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE \
- SD_ID128_MAKE(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
-#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR \
- SD_ID128_MAKE_STR(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
-
-#define SD_MESSAGE_NOBODY_USER_UNSUITABLE SD_ID128_MAKE(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
-#define SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR \
- SD_ID128_MAKE_STR(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
-
-#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED \
- SD_ID128_MAKE(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
-#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED_STR \
- SD_ID128_MAKE_STR(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
-
-#define SD_MESSAGE_TIME_SYNC SD_ID128_MAKE(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
-#define SD_MESSAGE_TIME_SYNC_STR SD_ID128_MAKE_STR(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
-
-#define SD_MESSAGE_LOGIND_SHUTDOWN SD_ID128_MAKE(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
-#define SD_MESSAGE_LOGIND_SHUTDOWN_STR SD_ID128_MAKE_STR(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
-
-#define SD_MESSAGE_LOGIND_SHUTDOWN_CANCELED \
- SD_ID128_MAKE(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
-#define SD_MESSAGE_LOGIND_SHUTDOWN_CANCELED_STR \
- SD_ID128_MAKE_STR(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
+/* And if you add a new ID here, make sure to generate a random one with "systemd-id128 new". Do not use any
+ * other IDs, and do not count them up manually. */
+
+#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
+#define SD_MESSAGE_JOURNAL_START_STR SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
+#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
+#define SD_MESSAGE_JOURNAL_STOP_STR SD_ID128_MAKE_STR(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
+#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
+#define SD_MESSAGE_JOURNAL_DROPPED_STR SD_ID128_MAKE_STR(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
+#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
+#define SD_MESSAGE_JOURNAL_MISSED_STR SD_ID128_MAKE_STR(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
+#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
+#define SD_MESSAGE_JOURNAL_USAGE_STR SD_ID128_MAKE_STR(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
+
+#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
+#define SD_MESSAGE_COREDUMP_STR SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
+#define SD_MESSAGE_TRUNCATED_CORE SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
+#define SD_MESSAGE_TRUNCATED_CORE_STR SD_ID128_MAKE_STR(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
+#define SD_MESSAGE_BACKTRACE SD_ID128_MAKE(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
+#define SD_MESSAGE_BACKTRACE_STR SD_ID128_MAKE_STR(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
+
+#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
+#define SD_MESSAGE_SESSION_START_STR SD_ID128_MAKE_STR(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
+#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
+#define SD_MESSAGE_SESSION_STOP_STR SD_ID128_MAKE_STR(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
+#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
+#define SD_MESSAGE_SEAT_START_STR SD_ID128_MAKE_STR(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
+#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
+#define SD_MESSAGE_SEAT_STOP_STR SD_ID128_MAKE_STR(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
+#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
+#define SD_MESSAGE_MACHINE_START_STR SD_ID128_MAKE_STR(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
+#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
+#define SD_MESSAGE_MACHINE_STOP_STR SD_ID128_MAKE_STR(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
+
+#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
+#define SD_MESSAGE_TIME_CHANGE_STR SD_ID128_MAKE_STR(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
+#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
+#define SD_MESSAGE_TIMEZONE_CHANGE_STR SD_ID128_MAKE_STR(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
+
+#define SD_MESSAGE_TAINTED SD_ID128_MAKE(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
+#define SD_MESSAGE_TAINTED_STR SD_ID128_MAKE_STR(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
+#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
+#define SD_MESSAGE_STARTUP_FINISHED_STR SD_ID128_MAKE_STR(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
+#define SD_MESSAGE_USER_STARTUP_FINISHED SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
+#define SD_MESSAGE_USER_STARTUP_FINISHED_STR SD_ID128_MAKE_STR(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
+
+#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
+#define SD_MESSAGE_SLEEP_START_STR SD_ID128_MAKE_STR(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
+#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
+#define SD_MESSAGE_SLEEP_STOP_STR SD_ID128_MAKE_STR(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
+
+#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
+#define SD_MESSAGE_SHUTDOWN_STR SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
+
+#define SD_MESSAGE_FACTORY_RESET SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
+#define SD_MESSAGE_FACTORY_RESET_STR SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
+
+/* The messages below are actually about jobs, not really about units, the macros are misleadingly named.
+ * Moreover SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job
+ * either finishes with SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
+#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
+#define SD_MESSAGE_UNIT_STARTING_STR SD_ID128_MAKE_STR(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
+#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
+#define SD_MESSAGE_UNIT_STARTED_STR SD_ID128_MAKE_STR(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
+#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
+#define SD_MESSAGE_UNIT_FAILED_STR SD_ID128_MAKE_STR(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
+#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
+#define SD_MESSAGE_UNIT_STOPPING_STR SD_ID128_MAKE_STR(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
+#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
+#define SD_MESSAGE_UNIT_STOPPED_STR SD_ID128_MAKE_STR(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
+#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
+#define SD_MESSAGE_UNIT_RELOADING_STR SD_ID128_MAKE_STR(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
+#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
+#define SD_MESSAGE_UNIT_RELOADED_STR SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
+
+#define SD_MESSAGE_UNIT_RESTART_SCHEDULED SD_ID128_MAKE(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
+#define SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR SD_ID128_MAKE_STR(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
+
+#define SD_MESSAGE_UNIT_RESOURCES SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+#define SD_MESSAGE_UNIT_RESOURCES_STR SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+
+#define SD_MESSAGE_UNIT_SUCCESS SD_ID128_MAKE(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
+#define SD_MESSAGE_UNIT_SUCCESS_STR SD_ID128_MAKE_STR(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
+#define SD_MESSAGE_UNIT_SKIPPED SD_ID128_MAKE(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
+#define SD_MESSAGE_UNIT_SKIPPED_STR SD_ID128_MAKE_STR(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
+#define SD_MESSAGE_UNIT_FAILURE_RESULT SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+
+#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
+#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
+
+#define SD_MESSAGE_UNIT_PROCESS_EXIT SD_ID128_MAKE(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
+#define SD_MESSAGE_UNIT_PROCESS_EXIT_STR SD_ID128_MAKE_STR(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
+
+#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
+#define SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR SD_ID128_MAKE_STR(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
+
+#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
+#define SD_MESSAGE_OVERMOUNTING_STR SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
+
+#define SD_MESSAGE_UNIT_OOMD_KILL SD_ID128_MAKE(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
+#define SD_MESSAGE_UNIT_OOMD_KILL_STR SD_ID128_MAKE_STR(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
+
+#define SD_MESSAGE_UNIT_OUT_OF_MEMORY SD_ID128_MAKE(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
+#define SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR SD_ID128_MAKE_STR(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
+
+#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
+#define SD_MESSAGE_LID_OPENED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
+#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
+#define SD_MESSAGE_LID_CLOSED_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
+#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
+#define SD_MESSAGE_SYSTEM_DOCKED_STR SD_ID128_MAKE_STR(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
+#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
+#define SD_MESSAGE_SYSTEM_UNDOCKED_STR SD_ID128_MAKE_STR(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
+#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
+#define SD_MESSAGE_POWER_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
+#define SD_MESSAGE_POWER_KEY_LONG_PRESS SD_ID128_MAKE(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
+#define SD_MESSAGE_POWER_KEY_LONG_PRESS_STR SD_ID128_MAKE_STR(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
+#define SD_MESSAGE_REBOOT_KEY SD_ID128_MAKE(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
+#define SD_MESSAGE_REBOOT_KEY_STR SD_ID128_MAKE_STR(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
+#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS SD_ID128_MAKE(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
+#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS_STR SD_ID128_MAKE_STR(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
+#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
+#define SD_MESSAGE_SUSPEND_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
+#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS SD_ID128_MAKE(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
+#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS_STR SD_ID128_MAKE_STR(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
+#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
+#define SD_MESSAGE_HIBERNATE_KEY_STR SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
+#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS SD_ID128_MAKE(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
+#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS_STR SD_ID128_MAKE_STR(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
+
+#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
+#define SD_MESSAGE_INVALID_CONFIGURATION_STR SD_ID128_MAKE_STR(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
+
+#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
+#define SD_MESSAGE_DNSSEC_FAILURE_STR SD_ID128_MAKE_STR(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
+#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
+#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR SD_ID128_MAKE_STR(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
+#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+
+#define SD_MESSAGE_UNSAFE_USER_NAME SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
+#define SD_MESSAGE_UNSAFE_USER_NAME_STR SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
+
+#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE SD_ID128_MAKE(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
+#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE_STR SD_ID128_MAKE_STR(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
+#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE SD_ID128_MAKE(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
+#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR SD_ID128_MAKE_STR(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
+
+#define SD_MESSAGE_NOBODY_USER_UNSUITABLE SD_ID128_MAKE(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
+#define SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR SD_ID128_MAKE_STR(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
+
+#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED SD_ID128_MAKE(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
+#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED_STR SD_ID128_MAKE_STR(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
+
+#define SD_MESSAGE_TIME_SYNC SD_ID128_MAKE(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
+#define SD_MESSAGE_TIME_SYNC_STR SD_ID128_MAKE_STR(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
+
+#define SD_MESSAGE_SHUTDOWN_SCHEDULED SD_ID128_MAKE(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
+#define SD_MESSAGE_SHUTDOWN_SCHEDULED_STR SD_ID128_MAKE_STR(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
+
+#define SD_MESSAGE_SHUTDOWN_CANCELED SD_ID128_MAKE(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
+#define SD_MESSAGE_SHUTDOWN_CANCELED_STR SD_ID128_MAKE_STR(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
_SD_END_DECLARATIONS;
break;
}
- r = fflush_and_check(passwd);
+ r = fflush_sync_and_check(passwd);
if (r < 0)
return log_debug_errno(r, "Failed to flush %s: %m", passwd_tmp);
ORDERED_HASHMAP_FOREACH(i, todo_uids) {
_cleanup_(erase_and_freep) char *creds_password = NULL;
- _cleanup_free_ char *cn = NULL;
+ bool is_hashed;
struct spwd n = {
.sp_namp = i->name,
.sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
};
- /* Try to pick up the password for this account via the credentials logic */
- cn = strjoin("passwd.hashed-password.", i->name);
- if (!cn)
- return -ENOMEM;
-
- r = read_credential(cn, (void**) &creds_password, NULL);
- if (r == -ENOENT) {
- _cleanup_(erase_and_freep) char *plaintext_password = NULL;
-
- free(cn);
- cn = strjoin("passwd.plaintext-password.", i->name);
- if (!cn)
- return -ENOMEM;
+ r = get_credential_user_password(i->name, &creds_password, &is_hashed);
+ if (r < 0)
+ log_debug_errno(r, "Couldn't read password credential for user '%s', ignoring: %m", i->name);
- r = read_credential(cn, (void**) &plaintext_password, NULL);
+ if (creds_password && !is_hashed) {
+ _cleanup_(erase_and_freep) char* plaintext_password = TAKE_PTR(creds_password);
+ r = hash_password(plaintext_password, &creds_password);
if (r < 0)
- log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
- else {
- r = hash_password(plaintext_password, &creds_password);
- if (r < 0)
- return log_debug_errno(r, "Failed to hash password: %m");
- }
- } else if (r < 0)
- log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+ return log_debug_errno(r, "Failed to hash password: %m");
+ }
if (creds_password)
n.sp_pwdp = creds_password;
return 0;
}
-static int gid_is_ok(gid_t gid) {
+static int gid_is_ok(gid_t gid, bool check_with_uid) {
struct group *g;
struct passwd *p;
return 0;
/* Avoid reusing gids that are already used by a different user */
- if (ordered_hashmap_get(todo_uids, UID_TO_PTR(gid)))
+ if (check_with_uid && ordered_hashmap_get(todo_uids, UID_TO_PTR(gid)))
return 0;
if (hashmap_contains(database_by_gid, GID_TO_PTR(gid)))
return 0;
- if (hashmap_contains(database_by_uid, UID_TO_PTR(gid)))
+ if (check_with_uid && hashmap_contains(database_by_uid, UID_TO_PTR(gid)))
return 0;
if (!arg_root) {
if (!IN_SET(errno, 0, ENOENT))
return -errno;
- errno = 0;
- p = getpwuid((uid_t) gid);
- if (p)
- return 0;
- if (!IN_SET(errno, 0, ENOENT))
- return -errno;
+ if (check_with_uid) {
+ errno = 0;
+ p = getpwuid((uid_t) gid);
+ if (p)
+ return 0;
+ if (!IN_SET(errno, 0, ENOENT))
+ return -errno;
+ }
}
return 1;
/* Try to use the suggested numeric GID */
if (i->gid_set) {
- r = gid_is_ok(i->gid);
+ r = gid_is_ok(i->gid, false);
if (r < 0)
return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
if (i->id_set_strict) {
/* Try to reuse the numeric uid, if there's one */
if (!i->gid_set && i->uid_set) {
- r = gid_is_ok((gid_t) i->uid);
+ r = gid_is_ok((gid_t) i->uid, true);
if (r < 0)
return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
if (r > 0) {
if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
else {
- r = gid_is_ok(c);
+ r = gid_is_ok(c, true);
if (r < 0)
return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
else if (r > 0) {
if (r < 0)
return log_error_errno(r, "No free group ID available for %s.", i->name);
- r = gid_is_ok(search_uid);
+ r = gid_is_ok(search_uid, true);
if (r < 0)
return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
else if (r > 0)
switch (i->type) {
case ADD_USER: {
- Item *j;
+ Item *j = NULL;
+
+ if (!i->gid_set)
+ j = ordered_hashmap_get(groups, i->group_name ?: i->name);
- j = ordered_hashmap_get(groups, i->group_name ?: i->name);
if (j && j->todo_group) {
/* When a group with the target name is already in queue,
* use the information about the group and do not create
assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "", "/zzz")), NULL));
}
+static void test_path_glob_can_match_one(const char *pattern, const char *prefix, const char *expected) {
+ _cleanup_free_ char *result = NULL;
+
+ log_debug("%s(%s, %s, %s)", __func__, pattern, prefix, strnull(expected));
+
+ assert_se(path_glob_can_match(pattern, prefix, &result) == !!expected);
+ assert_se(streq_ptr(result, expected));
+}
+
+TEST(path_glob_can_match) {
+ test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge/aaa/bbb", NULL);
+ test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge/aaa", "/foo/hoge/aaa");
+ test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge", "/foo/hoge/aaa");
+ test_path_glob_can_match_one("/foo/hoge/aaa", "/foo", "/foo/hoge/aaa");
+ test_path_glob_can_match_one("/foo/hoge/aaa", "/", "/foo/hoge/aaa");
+
+ test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge/aaa/bbb", NULL);
+ test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge/aaa", "/foo/hoge/aaa");
+ test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge", "/foo/hoge/aaa");
+ test_path_glob_can_match_one("/foo/*/aaa", "/foo", "/foo/*/aaa");
+ test_path_glob_can_match_one("/foo/*/aaa", "/", "/foo/*/aaa");
+
+ test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy/aaa/bbb", NULL);
+ test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy/aaa", "/foo/xxx/yyy/aaa");
+ test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy", "/foo/xxx/yyy/aaa");
+ test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx", "/foo/xxx/*/aaa");
+ test_path_glob_can_match_one("/foo/*/*/aaa", "/foo", "/foo/*/*/aaa");
+ test_path_glob_can_match_one("/foo/*/*/aaa", "/", "/foo/*/*/aaa");
+
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa/bbb/ccc", NULL);
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa/bbb", "/foo/xxx/aaa/bbb");
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/ccc", NULL);
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa", "/foo/xxx/aaa/*");
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx", "/foo/xxx/aaa/*");
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/foo", "/foo/*/aaa/*");
+ test_path_glob_can_match_one("/foo/*/aaa/*", "/", "/foo/*/aaa/*");
+}
+
TEST(print_MAX) {
log_info("PATH_MAX=%zu\n"
"FILENAME_MAX=%zu\n"
/* Take care to not iterate beyond the last valid track as specified in
* the TOC, but also avoid going beyond the TOC length, just in case
* the last track number is invalidly large */
- for (size_t i = 4; i + 8 < len && num_tracks > 0; i += 8, --num_tracks) {
+ for (size_t i = 4; i + 8 <= len && num_tracks > 0; i += 8, --num_tracks) {
bool is_data_track;
uint32_t block;
"Link\0"
"SR-IOV\0",
config_item_perf_lookup, link_config_gperf_lookup,
- CONFIG_PARSE_WARN, config, &stats_by_path);
+ CONFIG_PARSE_WARN, config, &stats_by_path,
+ NULL);
if (r < 0)
return r; /* config_parse_many() logs internally. */
}
/* called every couple of seconds during event activity; 'true' if config has changed */
-static bool builtin_hwdb_validate(void) {
- if (hwdb_validate(hwdb)) {
+static bool builtin_hwdb_should_reload(void) {
+ if (hwdb_should_reload(hwdb)) {
log_debug("hwdb needs reloading.");
return true;
}
.cmd = builtin_hwdb,
.init = builtin_hwdb_init,
.exit = builtin_hwdb_exit,
- .validate = builtin_hwdb_validate,
+ .should_reload = builtin_hwdb_should_reload,
.help = "Hardware database",
};
}
/* called every couple of seconds during event activity; 'true' if config has changed */
-static bool builtin_kmod_validate(void) {
+static bool builtin_kmod_should_reload(void) {
if (!ctx)
return false;
.cmd = builtin_kmod,
.init = builtin_kmod_init,
.exit = builtin_kmod_exit,
- .validate = builtin_kmod_validate,
+ .should_reload = builtin_kmod_should_reload,
.help = "Kernel module loader",
.run_once = false,
};
#include <linux/pci_regs.h>
#include "alloc-util.h"
+#include "chase-symlinks.h"
#include "device-util.h"
#include "dirent-util.h"
#include "fd-util.h"
NET_XENVIF,
NET_PLATFORM,
NET_NETDEVSIM,
+ NET_DEVICETREE,
} NetNameType;
typedef struct NetNames {
char xen_slot[ALTIFNAMSIZ];
char platform_path[ALTIFNAMSIZ];
char netdevsim_path[ALTIFNAMSIZ];
+ char devicetree_onboard[ALTIFNAMSIZ];
} NetNames;
/* skip intermediate virtio devices */
return 0;
}
+static int dev_devicetree_onboard(sd_device *dev, NetNames *names) {
+ _cleanup_(sd_device_unrefp) sd_device *aliases_dev = NULL, *ofnode_dev = NULL, *devicetree_dev = NULL;
+ const char *alias, *ofnode_path, *ofnode_syspath, *devicetree_syspath;
+ sd_device *parent;
+ int r;
+
+ if (!naming_scheme_has(NAMING_DEVICETREE_ALIASES))
+ return 0;
+
+ /* check if our direct parent has an of_node */
+ r = sd_device_get_parent(dev, &parent);
+ if (r < 0)
+ return r;
+
+ r = sd_device_new_child(&ofnode_dev, parent, "of_node");
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_syspath(ofnode_dev, &ofnode_syspath);
+ if (r < 0)
+ return r;
+
+ /* /proc/device-tree should be a symlink to /sys/firmware/devicetree/base. */
+ r = sd_device_new_from_path(&devicetree_dev, "/proc/device-tree");
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_syspath(devicetree_dev, &devicetree_syspath);
+ if (r < 0)
+ return r;
+
+ /*
+ * Example paths:
+ * devicetree_syspath = /sys/firmware/devicetree/base
+ * ofnode_syspath = /sys/firmware/devicetree/base/soc/ethernet@deadbeef
+ * ofnode_path = soc/ethernet@deadbeef
+ */
+ ofnode_path = path_startswith(ofnode_syspath, devicetree_syspath);
+ if (!ofnode_path)
+ return -ENOENT;
+
+ /* Get back our leading / to match the contents of the aliases */
+ ofnode_path--;
+ assert(path_is_absolute(ofnode_path));
+
+ r = sd_device_new_child(&aliases_dev, devicetree_dev, "aliases");
+ if (r < 0)
+ return r;
+
+ FOREACH_DEVICE_SYSATTR(aliases_dev, alias) {
+ const char *alias_path, *alias_index, *conflict;
+ unsigned i;
+
+ alias_index = startswith(alias, "ethernet");
+ if (!alias_index)
+ continue;
+
+ if (sd_device_get_sysattr_value(aliases_dev, alias, &alias_path) < 0)
+ continue;
+
+ if (!path_equal(ofnode_path, alias_path))
+ continue;
+
+ /* If there's no index, we default to 0... */
+ if (isempty(alias_index)) {
+ i = 0;
+ conflict = "ethernet0";
+ } else {
+ r = safe_atou(alias_index, &i);
+ if (r < 0)
+ return log_device_debug_errno(dev, r,
+ "Could not get index of alias %s: %m", alias);
+ conflict = "ethernet";
+ }
+
+ /* ...but make sure we don't have an alias conflict */
+ if (i == 0 && sd_device_get_sysattr_value(aliases_dev, conflict, NULL) >= 0)
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
+ "Ethernet alias conflict: ethernet and ethernet0 both exist");
+
+ xsprintf(names->devicetree_onboard, "d%u", i);
+ names->type = NET_DEVICETREE;
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
static int names_pci(sd_device *dev, const LinkInfo *info, NetNames *names) {
_cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL;
_cleanup_free_ char *virtfn_suffix = NULL;
ieee_oui(dev, &info, test);
}
+ /* get devicetree aliases; only ethernet supported for now */
+ if (streq(prefix, "en") && dev_devicetree_onboard(dev, &names) >= 0 &&
+ names.type == NET_DEVICETREE) {
+ char str[ALTIFNAMSIZ];
+
+ if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.devicetree_onboard))
+ udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
+ }
+
/* get path names for Linux on System z network devices */
if (names_ccw(dev, &names) >= 0 && names.type == NET_CCW) {
char str[ALTIFNAMSIZ];
log_debug("Unloaded link configuration context.");
}
-static bool builtin_net_setup_link_validate(void) {
+static bool builtin_net_setup_link_should_reload(void) {
if (!ctx)
return false;
.cmd = builtin_net_setup_link,
.init = builtin_net_setup_link_init,
.exit = builtin_net_setup_link_exit,
- .validate = builtin_net_setup_link_validate,
+ .should_reload = builtin_net_setup_link_should_reload,
.help = "Configure network link",
.run_once = false,
};
initialized = false;
}
-bool udev_builtin_validate(void) {
+bool udev_builtin_should_reload(void) {
for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
- if (builtins[i] && builtins[i]->validate && builtins[i]->validate())
+ if (builtins[i] && builtins[i]->should_reload && builtins[i]->should_reload())
return true;
return false;
}
const char *help;
int (*init)(void);
void (*exit)(void);
- bool (*validate)(void);
+ bool (*should_reload)(void);
bool run_once;
} UdevBuiltin;
bool udev_builtin_run_once(UdevBuiltinCommand cmd);
int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd, const char *command, bool test);
void udev_builtin_list(void);
-bool udev_builtin_validate(void);
+bool udev_builtin_should_reload(void);
int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val);
int udev_builtin_hwdb_lookup(sd_device *dev, const char *prefix, const char *modalias,
const char *filter, bool test);
mac_selinux_maybe_reload();
/* Nothing changed. It is not necessary to reload. */
- if (!udev_rules_should_reload(manager->rules) && !udev_builtin_validate())
+ if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload())
return;
sd_notify(false,
if (r < 0)
return r;
+ (void) sd_device_monitor_set_description(worker_monitor, "worker");
+
/* allow the main daemon netlink address to send devices to the worker */
r = device_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
if (r < 0)
log_warning_errno(r, "Failed to set receive buffer size for device monitor, ignoring: %m");
}
+ (void) sd_device_monitor_set_description(manager->monitor, "manager");
+
r = device_monitor_enable_receiving(manager->monitor);
if (r < 0)
return log_error_errno(r, "Failed to bind netlink socket: %m");
Group=
PacketInfo=
VNetHeader=
+KeepCarrier=
[IPVLAN]
Mode=
Flags=
VNetHeader=
Group=
User=
+KeepCarrier=
[NetDev]
Kind=
MACAddress=
self.assertEqual(self.read_attr('port2', 'brport/path_cost'), '555')
self.assertEqual(self.read_attr('port2', 'brport/multicast_fast_leave'), '1')
self.assertEqual(self.read_attr('port2', 'brport/unicast_flood'), '1')
- self.assertEqual(self.read_attr('port2', 'brport/bpdu_guard'), '1')
- self.assertEqual(self.read_attr('port2', 'brport/root_block'), '1')
+ self.assertEqual(self.read_attr('port2', 'brport/bpdu_guard'), '0')
+ self.assertEqual(self.read_attr('port2', 'brport/root_block'), '0')
class ClientTestBase(NetworkdTestingUtilities):
"""Provide common methods for testing networkd against servers."""
chmod +x "$initdir/opt/script1.sh"
echo MARKER=1 >"$initdir/usr/lib/systemd/system/other_file"
mksquashfs "$initdir" "$oldinitdir/usr/share/app1.raw" -noappend
+
+ export initdir="$TESTDIR/app-nodistro"
+ mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system"
+ ( echo "ID=_any"
+ echo "ARCHITECTURE=_any" ) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro"
+ echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file"
+ mksquashfs "$initdir" "$oldinitdir/usr/share/app-nodistro.raw" -noappend
)
}
[Match]
Name=bridge99
+[Link]
+MTUBytes=9000
+
[Network]
Address=192.168.0.15/24
Gateway=192.168.0.1
+++ /dev/null
-# SPDX-License-Identifier: LGPL-2.1-or-later
-[Match]
-Name=veth99
-
-[Network]
-DHCP=ipv4
-IPv6AcceptRA=false
-
-[DHCPv4]
-SendDecline=yes
[DHCPv4]
Use6RD=yes
+SendDecline=yes
[DHCPPrefixDelegation]
UplinkInterface=:self
+++ /dev/null
-# SPDX-License-Identifier: LGPL-2.1-or-later
-[Match]
-Name=dummy98
-
-[Network]
-IPv6AcceptRA=no
-Address=10.1.2.3/16
-
-[QDisc]
-Parent=clsact
-
-[HierarchyTokenBucket]
-Parent=root
-Handle=0002
-DefaultClass=30
-RateToQuantum=20
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0030
-Priority=1
-QuantumBytes=4000
-MTUBytes=1700
-OverheadBytes=100
-Rate=1M
-BufferBytes=123456
-CeilRate=0.5M
-CeilBufferBytes=123457
-
-[NetworkEmulator]
-Parent=2:30
-Handle=0030
-DelaySec=50ms
-DelayJitterSec=10ms
-LossRate=20%
-PacketLimit=100
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0031
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[TrivialLinkEqualizer]
-Parent=2:31
-Handle=0031
-Id=1
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0032
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[FairQueueing]
-Parent=2:32
-Handle=0032
-PacketLimit=1000
-FlowLimit=200
-QuantumBytes=1500
-InitialQuantumBytes=13000
-MaximumRate=1M
-Buckets=512
-OrphanMask=511
-Pacing=yes
-CEThresholdSec=100ms
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0033
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[ControlledDelay]
-Parent=2:33
-Handle=0033
-PacketLimit=2000
-TargetSec=10ms
-IntervalSec=50ms
-ECN=yes
-CEThresholdSec=100ms
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0034
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[FairQueueingControlledDelay]
-Parent=2:34
-Handle=0034
-PacketLimit=20480
-MemoryLimitBytes=64M
-Flows=2048
-TargetSec=10ms
-IntervalSec=200ms
-QuantumBytes=1400
-ECN=yes
-CEThresholdSec=100ms
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0035
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[TokenBucketFilter]
-Parent=2:35
-Handle=0035
-Rate=1G
-BurstBytes=5000
-LatencySec=70msec
-PeakRate=100G
-MTUBytes=1000000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0036
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[StochasticFairnessQueueing]
-Parent=2:36
-Handle=0036
-PerturbPeriodSec=5sec
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0037
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[PFIFO]
-Parent=2:37
-Handle=0037
-PacketLimit=100000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0038
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[GenericRandomEarlyDetection]
-Parent=2:38
-Handle=0038
-VirtualQueues=12
-DefaultVirtualQueue=10
-GenericRIO=yes
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0039
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[StochasticFairBlue]
-Parent=2:39
-Handle=0039
-PacketLimit=200000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:003a
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[BFIFO]
-Parent=2:3a
-Handle=003a
-LimitBytes=1000000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:003b
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[PFIFOHeadDrop]
-Parent=2:3b
-Handle=003b
-PacketLimit=1023
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:003c
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[PFIFOFast]
-Parent=2:3c
-Handle=003c
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[QDisc]
+Parent=clsact
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[ControlledDelay]
+Parent=root
+Handle=0033
+PacketLimit=2000
+TargetSec=10ms
+IntervalSec=50ms
+ECN=yes
+CEThresholdSec=100ms
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[FairQueueing]
+Parent=root
+Handle=0032
+PacketLimit=1000
+FlowLimit=200
+QuantumBytes=1500
+InitialQuantumBytes=13000
+MaximumRate=1M
+Buckets=512
+OrphanMask=511
+Pacing=yes
+CEThresholdSec=100ms
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[FairQueueingControlledDelay]
+Parent=root
+Handle=0034
+PacketLimit=20480
+MemoryLimitBytes=64M
+Flows=2048
+TargetSec=10ms
+IntervalSec=200ms
+QuantumBytes=1400
+ECN=yes
+CEThresholdSec=100ms
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[GenericRandomEarlyDetection]
+Parent=root
+Handle=0038
+VirtualQueues=12
+DefaultVirtualQueue=10
+GenericRIO=yes
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[HierarchyTokenBucket]
+Parent=root
+Handle=0002
+DefaultClass=30
+RateToQuantum=20
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:0037
+Priority=1
+Rate=1M
+CeilRate=0.5M
+QuantumBytes=4000
+MTUBytes=1700
+OverheadBytes=100
+BufferBytes=123456
+CeilBufferBytes=123457
+
+[PFIFO]
+Parent=2:37
+Handle=0037
+PacketLimit=100000
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003a
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[BFIFO]
+Parent=2:3a
+Handle=003a
+LimitBytes=1000000
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003b
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[PFIFOHeadDrop]
+Parent=2:3b
+Handle=003b
+PacketLimit=1023
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003c
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[PFIFOFast]
+Parent=2:3c
+Handle=003c
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=test1
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.4/16
+
+[QDisc]
+Parent=ingress
NetworkEmulatorDelayJitterSec=10ms
NetworkEmulatorLossRate=20%
NetworkEmulatorPacketLimit=100
-
-[TrafficControlQueueingDiscipline]
-Parent=ingress
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[NetworkEmulator]
+Parent=root
+Handle=0030
+DelaySec=50ms
+DelayJitterSec=10ms
+LossRate=20%
+PacketLimit=100
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
-Name=test1
+Name=dummy98
[Network]
IPv6AcceptRA=no
-Address=10.1.2.4/16
+Address=10.1.2.3/16
[QuickFairQueueing]
Parent=root
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[StochasticFairBlue]
+Parent=root
+Handle=0039
+PacketLimit=200000
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[StochasticFairnessQueueing]
+Parent=root
+Handle=0036
+PerturbPeriodSec=5sec
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[TokenBucketFilter]
+Parent=root
+Handle=0035
+Rate=1G
+BurstBytes=5000
+LatencySec=70msec
+PeakRate=100G
+MTUBytes=1000000
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[TrivialLinkEqualizer]
+Parent=root
+Handle=0031
+Id=1
# SPDX-License-Identifier: LGPL-2.1-or-later
[NetDev]
-Name=tap99
+Name=testtap99
Kind=tap
[Tap]
MultiQueue=true
PacketInfo=true
VNetHeader=true
+KeepCarrier=yes
# SPDX-License-Identifier: LGPL-2.1-or-later
[NetDev]
-Name=tun99
+Name=testtun99
Kind=tun
[Tun]
MultiQueue=true
PacketInfo=true
VNetHeader=true
+KeepCarrier=yes
[Match]
Name=dummy98
+[Link]
+MTUBytes=9000
+
[Network]
Bridge=bridge99
[Match]
Name=test1
+[Link]
+MTUBytes=9000
+
[Network]
Bridge=bridge99
Name=xfrm98 xfrm99
Name=vxlan98
Name=hogehogehogehogehogehoge
+Name=testtun99
+Name=testtap99
[Network]
LinkLocalAddressing=yes
import itertools
import os
import pathlib
+import psutil
import re
import shutil
import signal
networkd_bin = shutil.which('systemd-networkd', path=which_paths)
resolved_bin = shutil.which('systemd-resolved', path=which_paths)
+timesyncd_bin = shutil.which('systemd-timesyncd', path=which_paths)
udevd_bin = shutil.which('systemd-udevd', path=which_paths)
wait_online_bin = shutil.which('systemd-networkd-wait-online', path=which_paths)
networkctl_bin = shutil.which('networkctl', path=which_paths)
resolvectl_bin = shutil.which('resolvectl', path=which_paths)
timedatectl_bin = shutil.which('timedatectl', path=which_paths)
+udevadm_bin = shutil.which('udevadm', path=which_paths)
use_valgrind = False
+valgrind_cmd = ''
enable_debug = True
env = {}
wait_online_env = {}
def touch(path):
pathlib.Path(path).touch()
-def check_output(*command, text=True, **kwargs):
+def check_output(*command, **kwargs):
# This checks the result and returns stdout (and stderr) on success.
command = command[0].split() + list(command[1:])
- return subprocess.run(command, check=True, universal_newlines=text, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs).stdout.rstrip()
-
-def call(*command, text=True, **kwargs):
+ ret = subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs)
+ if ret.returncode == 0:
+ return ret.stdout.rstrip()
+ # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
+ print(ret.stdout)
+ ret.check_returncode()
+
+def call(*command, **kwargs):
# This returns returncode. stdout and stderr are merged and shown in console
command = command[0].split() + list(command[1:])
- return subprocess.run(command, check=False, universal_newlines=text, stderr=subprocess.STDOUT, **kwargs).returncode
+ return subprocess.run(command, check=False, universal_newlines=True, stderr=subprocess.STDOUT, **kwargs).returncode
-def call_quiet(*command, text=True, **kwargs):
+def call_quiet(*command, **kwargs):
command = command[0].split() + list(command[1:])
- return subprocess.run(command, check=False, universal_newlines=text, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs).returncode
+ return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs).returncode
-def run(*command, text=True, **kwargs):
+def run(*command, **kwargs):
# This returns CompletedProcess instance.
command = command[0].split() + list(command[1:])
- return subprocess.run(command, check=False, universal_newlines=text, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
+ return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
-def is_module_available(module_name):
- lsmod_output = check_output('lsmod')
- module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
- return module_re.search(lsmod_output) or call_quiet('modprobe', module_name) == 0
+def is_module_available(*module_names):
+ for module_name in module_names:
+ lsmod_output = check_output('lsmod')
+ module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
+ if not module_re.search(lsmod_output) and call_quiet('modprobe', module_name) != 0:
+ return False
+ return True
-def expectedFailureIfModuleIsNotAvailable(module_name):
+def expectedFailureIfModuleIsNotAvailable(*module_names):
def f(func):
- return func if is_module_available(module_name) else unittest.expectedFailure(func)
+ return func if is_module_available(*module_names) else unittest.expectedFailure(func)
return f
return f
-def expectedFailureIfCAKEIsNotAvailable():
- def f(func):
- call_quiet('ip link add dummy98 type dummy')
- rc = call_quiet('tc qdisc add dev dummy98 parent root cake')
- remove_link('dummy98')
- return func if rc == 0 else unittest.expectedFailure(func)
-
- return f
-
-def expectedFailureIfPIEIsNotAvailable():
- def f(func):
- call_quiet('ip link add dummy98 type dummy')
- rc = call_quiet('tc qdisc add dev dummy98 parent root pie')
- remove_link('dummy98')
- return func if rc == 0 else unittest.expectedFailure(func)
-
- return f
-
-def expectedFailureIfHHFIsNotAvailable():
- def f(func):
- call_quiet('ip link add dummy98 type dummy')
- rc = call_quiet('tc qdisc add dev dummy98 parent root hhf')
- remove_link('dummy98')
- return func if rc == 0 else unittest.expectedFailure(func)
-
- return f
-
-def expectedFailureIfETSIsNotAvailable():
- def f(func):
- call_quiet('ip link add dummy98 type dummy')
- rc = call_quiet('tc qdisc add dev dummy98 parent root ets bands 10')
- remove_link('dummy98')
- return func if rc == 0 else unittest.expectedFailure(func)
-
- return f
-
-def expectedFailureIfFQPIEIsNotAvailable():
- def f(func):
- call_quiet('ip link add dummy98 type dummy')
- rc = call_quiet('tc qdisc add dev dummy98 parent root fq_pie')
- remove_link('dummy98')
- return func if rc == 0 else unittest.expectedFailure(func)
-
- return f
-
def udev_reload():
- check_output('udevadm control --reload')
+ check_output(*udevadm_cmd, 'control', '--reload')
def copy_network_unit(*units, copy_dropins=True):
"""
def save_active_units():
for u in ['systemd-networkd.socket', 'systemd-networkd.service',
- 'systemd-resolved.service',
+ 'systemd-resolved.service', 'systemd-timesyncd.service',
'firewalld.service']:
if call(f'systemctl is-active --quiet {u}') == 0:
call(f'systemctl stop {u}')
for u in active_units:
call(f'systemctl restart {u}')
+def create_unit_dropin(unit, contents):
+ mkdir_p(f'/run/systemd/system/{unit}.d')
+ with open(f'/run/systemd/system/{unit}.d/00-override.conf', mode='w', encoding='utf-8') as f:
+ f.write('\n'.join(contents))
+
+def create_service_dropin(service, command, reload_command=None, additional_settings=None):
+ drop_in = [
+ '[Service]',
+ 'ExecStart=',
+ f'ExecStart=!!{valgrind_cmd}{command}',
+ ]
+ if reload_command:
+ drop_in += [
+ 'ExecReload=',
+ f'ExecReload={valgrind_cmd}{reload_command}',
+ ]
+ if enable_debug:
+ drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
+ if asan_options:
+ drop_in += [f'Environment=ASAN_OPTIONS="{asan_options}"']
+ if lsan_options:
+ drop_in += [f'Environment=LSAN_OPTIONS="{lsan_options}"']
+ if ubsan_options:
+ drop_in += [f'Environment=UBSAN_OPTIONS="{ubsan_options}"']
+ if asan_options or lsan_options or ubsan_options:
+ drop_in += ['SystemCallFilter=']
+ if use_valgrind or asan_options or lsan_options or ubsan_options:
+ drop_in += ['MemoryDenyWriteExecute=no']
+ if use_valgrind:
+ drop_in += [
+ 'Environment=SYSTEMD_MEMPOOL=0',
+ 'PrivateTmp=yes',
+ ]
+ if with_coverage:
+ drop_in += [
+ 'ProtectSystem=no',
+ 'ProtectHome=no',
+ ]
+ if additional_settings:
+ drop_in += additional_settings
+
+ create_unit_dropin(f'{service}.service', drop_in)
+
def link_exists(link):
return os.path.exists(os.path.join('/sys/class/net', link, 'ifindex'))
def save_timezone():
global saved_timezone
- r = run('timedatectl show --value --property Timezone')
+ r = run(*timedatectl_cmd, 'show', '--value', '--property', 'Timezone', env=env)
if r.returncode == 0:
saved_timezone = r.stdout.rstrip()
print(f'### Saved timezone: {saved_timezone}')
def restore_timezone():
if saved_timezone:
- call(f'timedatectl set-timezone {saved_timezone}')
+ call(*timedatectl_cmd, 'set-timezone', f'{saved_timezone}', env=env)
def read_link_attr(*args):
with open(os.path.join('/sys/class/net', *args), encoding='utf-8') as f:
check_output('systemctl start systemd-networkd')
def restart_networkd(show_logs=True):
- stop_networkd(show_logs)
- start_networkd()
+ if show_logs:
+ invocation_id = check_output('systemctl show systemd-networkd.service -p InvocationID --value')
+ check_output('systemctl restart systemd-networkd.service')
+ if show_logs:
+ print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id))
+
+def networkd_pid():
+ return int(check_output('systemctl show --value -p MainPID systemd-networkd.service'))
def networkctl_reconfigure(*links):
check_output(*networkctl_cmd, 'reconfigure', *links, env=env)
save_routing_policy_rules()
save_timezone()
- drop_in = [
- '[Unit]',
- 'StartLimitIntervalSec=0',
- '[Service]',
- 'Restart=no',
- 'ExecStart=',
- 'ExecReload=',
- ]
- if use_valgrind:
- drop_in += [
- 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin,
- f'ExecReload=valgrind {networkctl_bin} reload',
- 'PrivateTmp=yes'
+ create_service_dropin('systemd-networkd', networkd_bin,
+ f'{networkctl_bin} reload',
+ ['[Service]', 'Restart=no', '[Unit]', 'StartLimitIntervalSec=0'])
+ create_service_dropin('systemd-resolved', resolved_bin)
+ create_service_dropin('systemd-timesyncd', timesyncd_bin)
+
+ # TODO: also run udevd with sanitizers, valgrind, or coverage
+ #create_service_dropin('systemd-udevd', udevd_bin,
+ # f'{udevadm_bin} control --reload --timeout 0')
+ create_unit_dropin(
+ 'systemd-udevd.service',
+ [
+ '[Service]',
+ 'ExecStart=',
+ f'ExecStart=!!{udevd_bin}',
+ 'ExecReload=',
+ f'ExecReload={udevadm_bin} control --reload --timeout 0',
]
- else:
- drop_in += [
- 'ExecStart=!!' + networkd_bin,
- f'ExecReload={networkctl_bin} reload',
- ]
- if enable_debug:
- drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
- if asan_options:
- drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
- if lsan_options:
- drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
- if ubsan_options:
- drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
- if asan_options or lsan_options or ubsan_options:
- drop_in += ['SystemCallFilter=']
- if use_valgrind or asan_options or lsan_options or ubsan_options:
- drop_in += ['MemoryDenyWriteExecute=no']
- if with_coverage:
- drop_in += [
- 'ProtectSystem=no',
- 'ProtectHome=no',
+ )
+ create_unit_dropin(
+ 'systemd-networkd.socket',
+ [
+ '[Unit]',
+ 'StartLimitIntervalSec=0',
]
-
- mkdir_p('/run/systemd/system/systemd-networkd.service.d')
- with open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
- f.write('\n'.join(drop_in))
-
- drop_in = [
- '[Service]',
- 'Restart=no',
- 'ExecStart=',
- ]
- if use_valgrind:
- drop_in += ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin]
- else:
- drop_in += ['ExecStart=!!' + resolved_bin]
- if enable_debug:
- drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
- if asan_options:
- drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
- if lsan_options:
- drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
- if ubsan_options:
- drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
- if asan_options or lsan_options or ubsan_options:
- drop_in += ['SystemCallFilter=']
- if use_valgrind or asan_options or lsan_options or ubsan_options:
- drop_in += ['MemoryDenyWriteExecute=no']
- if with_coverage:
- drop_in += [
- 'ProtectSystem=no',
- 'ProtectHome=no',
- ]
-
- mkdir_p('/run/systemd/system/systemd-resolved.service.d')
- with open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
- f.write('\n'.join(drop_in))
-
- drop_in = [
- '[Service]',
- 'ExecStart=',
- 'ExecStart=!!' + udevd_bin,
- ]
-
- mkdir_p('/run/systemd/system/systemd-udevd.service.d')
- with open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
- f.write('\n'.join(drop_in))
+ )
check_output('systemctl daemon-reload')
print(check_output('systemctl cat systemd-networkd.service'))
print(check_output('systemctl cat systemd-resolved.service'))
+ print(check_output('systemctl cat systemd-timesyncd.service'))
print(check_output('systemctl cat systemd-udevd.service'))
check_output('systemctl restart systemd-resolved.service')
+ check_output('systemctl restart systemd-timesyncd.service')
check_output('systemctl restart systemd-udevd.service')
def tearDownModule():
restore_timezone()
rm_rf('/run/systemd/system/systemd-networkd.service.d')
+ rm_rf('/run/systemd/system/systemd-networkd.socket.d')
rm_rf('/run/systemd/system/systemd-resolved.service.d')
+ rm_rf('/run/systemd/system/systemd-timesyncd.service.d')
rm_rf('/run/systemd/system/systemd-udevd.service.d')
check_output('systemctl daemon-reload')
check_output('systemctl restart systemd-udevd.service')
try:
check_output(*args, env=wait_online_env)
except subprocess.CalledProcessError as e:
- print(e.stdout) # show logs only on failure
+ # show detailed status on failure
for link in links_with_operstate:
name = link.split(':')[0]
if link_exists(name):
self.assertRegex(output, 'link/ether 12:34:56:78:9a:bf')
self.assertRegex(output, 'mtu 1800')
- def test_tun(self):
- copy_network_unit('25-tun.netdev')
+ def test_tuntap(self):
+ copy_network_unit('25-tun.netdev', '25-tap.netdev', '26-netdev-link-local-addressing-yes.network')
start_networkd()
- self.wait_online(['tun99:off'], setup_state='unmanaged')
+ self.wait_online(['testtun99:degraded', 'testtap99:degraded'])
+
+ pid = networkd_pid()
+ name = psutil.Process(pid).name()[:15]
- output = check_output('ip -d link show tun99')
+ output = check_output('ip -d tuntap show')
+ print(output)
+ self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+ self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+
+ output = check_output('ip -d link show testtun99')
print(output)
# Old ip command does not support IFF_ flags
self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
+ self.assertIn('UP,LOWER_UP', output)
- def test_tap(self):
- copy_network_unit('25-tap.netdev')
- start_networkd()
+ output = check_output('ip -d link show testtap99')
+ print(output)
+ self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
+ self.assertIn('UP,LOWER_UP', output)
- self.wait_online(['tap99:off'], setup_state='unmanaged')
+ remove_network_unit('26-netdev-link-local-addressing-yes.network')
- output = check_output('ip -d link show tap99')
+ restart_networkd()
+ self.wait_online(['testtun99:degraded', 'testtap99:degraded'], setup_state='unmanaged')
+
+ pid = networkd_pid()
+ name = psutil.Process(pid).name()[:15]
+
+ output = check_output('ip -d tuntap show')
+ print(output)
+ self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+ self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+
+ output = check_output('ip -d link show testtun99')
+ print(output)
+ self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
+ self.assertIn('UP,LOWER_UP', output)
+
+ output = check_output('ip -d link show testtap99')
print(output)
- # Old ip command does not support IFF_ flags
self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
+ self.assertIn('UP,LOWER_UP', output)
+
+ clear_network_units()
+ restart_networkd()
+ self.wait_online(['testtun99:off', 'testtap99:off'], setup_state='unmanaged')
+
+ output = check_output('ip -d tuntap show')
+ print(output)
+ self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
+ self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
+
+ for i in range(10):
+ if i != 0:
+ time.sleep(1)
+ output = check_output('ip -d link show testtun99')
+ print(output)
+ self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
+ if 'NO-CARRIER' in output:
+ break
+ else:
+ self.fail()
+
+ for i in range(10):
+ if i != 0:
+ time.sleep(1)
+ output = check_output('ip -d link show testtap99')
+ print(output)
+ self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
+ if 'NO-CARRIER' in output:
+ break
+ else:
+ self.fail()
@expectedFailureIfModuleIsNotAvailable('vrf')
def test_vrf(self):
def tearDown(self):
tear_down_common()
- @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
+ @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_netlink')
def test_l2tp_udp(self):
copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
'25-l2tp-udp.netdev', '25-l2tp.network')
self.assertRegex(output, "Peer session 18, tunnel 11")
self.assertRegex(output, "interface name: l2tp-ses2")
- @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
+ @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_ip', 'l2tp_netlink')
def test_l2tp_ip(self):
copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
'25-l2tp-ip.netdev', '25-l2tp.network')
print(output)
self.assertEqual(output, '')
- def test_qdisc(self):
- copy_network_unit('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
- '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
- check_output('modprobe sch_teql max_equalizers=2')
+class NetworkdTCTests(unittest.TestCase, Utilities):
+
+ def setUp(self):
+ setup_common()
+
+ def tearDown(self):
+ tear_down_common()
+
+ @expectedFailureIfModuleIsNotAvailable('sch_cake')
+ def test_qdisc_cake(self):
+ copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
start_networkd()
- self.wait_online(['dummy98:routable', 'test1:routable'])
+ self.wait_online(['dummy98:routable'])
- output = check_output('tc qdisc show dev test1')
+ output = check_output('tc qdisc show dev dummy98')
print(output)
- self.assertRegex(output, 'qdisc netem')
- self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
- self.assertRegex(output, 'qdisc ingress')
+ self.assertIn('qdisc cake 3a: root', output)
+ self.assertIn('bandwidth 500Mbit', output)
+ self.assertIn('autorate-ingress', output)
+ self.assertIn('diffserv8', output)
+ self.assertIn('dual-dsthost', output)
+ self.assertIn(' nat', output)
+ self.assertIn(' wash', output)
+ self.assertIn(' split-gso', output)
+ self.assertIn(' raw', output)
+ self.assertIn(' atm', output)
+ self.assertIn('overhead 128', output)
+ self.assertIn('mpu 20', output)
+ self.assertIn('fwmark 0xff00', output)
+
+ @expectedFailureIfModuleIsNotAvailable('sch_codel')
+ def test_qdisc_codel(self):
+ copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
- self.assertRegex(output, 'qdisc clsact')
+ self.assertRegex(output, 'qdisc codel 33: root')
+ self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
- self.assertRegex(output, 'qdisc htb 2: root')
- self.assertRegex(output, r'default (0x30|30)')
+ @expectedFailureIfModuleIsNotAvailable('sch_drr')
+ def test_qdisc_drr(self):
+ copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
- self.assertRegex(output, 'qdisc netem 30: parent 2:30')
- self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
- self.assertRegex(output, 'qdisc fq_codel')
- self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc drr 2: root')
+ output = check_output('tc class show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
- self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
+ @expectedFailureIfModuleIsNotAvailable('sch_ets')
+ def test_qdisc_ets(self):
+ copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
- self.assertRegex(output, 'qdisc fq 32: parent 2:32')
+ self.assertRegex(output, 'qdisc ets 3a: root')
+ self.assertRegex(output, 'bands 10 strict 3')
+ self.assertRegex(output, 'quanta 1 2 3 4 5')
+ self.assertRegex(output, 'priomap 3 4 5 6 7')
+
+ @expectedFailureIfModuleIsNotAvailable('sch_fq')
+ def test_qdisc_fq(self):
+ copy_network_unit('25-qdisc-fq.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc fq 32: root')
self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
self.assertRegex(output, 'quantum 1500')
self.assertRegex(output, 'initial_quantum 13000')
self.assertRegex(output, 'maxrate 1Mbit')
- self.assertRegex(output, 'qdisc codel 33: parent 2:33')
- self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
+ @expectedFailureIfModuleIsNotAvailable('sch_fq_codel')
+ def test_qdisc_fq_codel(self):
+ copy_network_unit('25-qdisc-fq_codel.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
- self.assertRegex(output, 'qdisc fq_codel 34: parent 2:34')
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc fq_codel 34: root')
self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
- self.assertRegex(output, 'qdisc tbf 35: parent 2:35')
- self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
+ @expectedFailureIfModuleIsNotAvailable('sch_fq_pie')
+ def test_qdisc_fq_pie(self):
+ copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
- self.assertRegex(output, 'qdisc sfq 36: parent 2:36')
- self.assertRegex(output, 'perturb 5sec')
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
- self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
- self.assertRegex(output, 'limit 100000p')
+ self.assertRegex(output, 'qdisc fq_pie 3a: root')
+ self.assertRegex(output, 'limit 200000p')
- self.assertRegex(output, 'qdisc gred 38: parent 2:38')
+ @expectedFailureIfModuleIsNotAvailable('sch_gred')
+ def test_qdisc_gred(self):
+ copy_network_unit('25-qdisc-gred.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc gred 38: root')
self.assertRegex(output, 'vqs 12 default 10 grio')
- self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
- self.assertRegex(output, 'limit 200000')
+ @expectedFailureIfModuleIsNotAvailable('sch_hhf')
+ def test_qdisc_hhf(self):
+ copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc hhf 3a: root')
+ self.assertRegex(output, 'limit 1022p')
+
+ @expectedFailureIfModuleIsNotAvailable('sch_htb')
+ def test_qdisc_htb_fifo(self):
+ copy_network_unit('25-qdisc-htb-fifo.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc htb 2: root')
+ self.assertRegex(output, r'default (0x30|30)')
+
+ self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
+ self.assertRegex(output, 'limit 100000p')
self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
self.assertRegex(output, 'limit 1000000')
output = check_output('tc -d class show dev dummy98')
print(output)
- self.assertRegex(output, 'class htb 2:30 root leaf 30:')
- self.assertRegex(output, 'class htb 2:31 root leaf 31:')
- self.assertRegex(output, 'class htb 2:32 root leaf 32:')
- self.assertRegex(output, 'class htb 2:33 root leaf 33:')
- self.assertRegex(output, 'class htb 2:34 root leaf 34:')
- self.assertRegex(output, 'class htb 2:35 root leaf 35:')
- self.assertRegex(output, 'class htb 2:36 root leaf 36:')
self.assertRegex(output, 'class htb 2:37 root leaf 37:')
- self.assertRegex(output, 'class htb 2:38 root leaf 38:')
- self.assertRegex(output, 'class htb 2:39 root leaf 39:')
self.assertRegex(output, 'class htb 2:3a root leaf 3a:')
self.assertRegex(output, 'class htb 2:3b root leaf 3b:')
self.assertRegex(output, 'class htb 2:3c root leaf 3c:')
self.assertRegex(output, 'burst 123456')
self.assertRegex(output, 'cburst 123457')
- def test_qdisc2(self):
- copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev',
- '25-qdisc-qfq.network', '11-dummy.netdev')
+ @expectedFailureIfModuleIsNotAvailable('sch_ingress')
+ def test_qdisc_ingress(self):
+ copy_network_unit('25-qdisc-clsact.network', '12-dummy.netdev',
+ '25-qdisc-ingress.network', '11-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable', 'test1:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
- self.assertRegex(output, 'qdisc drr 2: root')
- output = check_output('tc class show dev dummy98')
- print(output)
- self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
+ self.assertRegex(output, 'qdisc clsact')
output = check_output('tc qdisc show dev test1')
print(output)
- self.assertRegex(output, 'qdisc qfq 2: root')
- output = check_output('tc class show dev test1')
- print(output)
- self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
- self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
+ self.assertRegex(output, 'qdisc ingress')
- @expectedFailureIfCAKEIsNotAvailable()
- def test_qdisc_cake(self):
- copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
+ @expectedFailureIfModuleIsNotAvailable('sch_netem')
+ def test_qdisc_netem(self):
+ copy_network_unit('25-qdisc-netem.network', '12-dummy.netdev',
+ '25-qdisc-netem-compat.network', '11-dummy.netdev')
start_networkd()
- self.wait_online(['dummy98:routable'])
+ self.wait_online(['dummy98:routable', 'test1:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
- self.assertIn('qdisc cake 3a: root', output)
- self.assertIn('bandwidth 500Mbit', output)
- self.assertIn('autorate-ingress', output)
- self.assertIn('diffserv8', output)
- self.assertIn('dual-dsthost', output)
- self.assertIn(' nat', output)
- self.assertIn(' wash', output)
- self.assertIn(' split-gso', output)
- self.assertIn(' raw', output)
- self.assertIn(' atm', output)
- self.assertIn('overhead 128', output)
- self.assertIn('mpu 20', output)
- self.assertIn('fwmark 0xff00', output)
+ self.assertRegex(output, 'qdisc netem 30: root')
+ self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
- @expectedFailureIfPIEIsNotAvailable()
+ output = check_output('tc qdisc show dev test1')
+ print(output)
+ self.assertRegex(output, 'qdisc netem [0-9a-f]*: root')
+ self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
+
+ @expectedFailureIfModuleIsNotAvailable('sch_pie')
def test_qdisc_pie(self):
copy_network_unit('25-qdisc-pie.network', '12-dummy.netdev')
start_networkd()
self.assertRegex(output, 'qdisc pie 3a: root')
self.assertRegex(output, 'limit 200000')
- @expectedFailureIfHHFIsNotAvailable()
- def test_qdisc_hhf(self):
- copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
+ @expectedFailureIfModuleIsNotAvailable('sch_qfq')
+ def test_qdisc_qfq(self):
+ copy_network_unit('25-qdisc-qfq.network', '12-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
- self.assertRegex(output, 'qdisc hhf 3a: root')
- self.assertRegex(output, 'limit 1022p')
+ self.assertRegex(output, 'qdisc qfq 2: root')
+ output = check_output('tc class show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
+ self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
- @expectedFailureIfETSIsNotAvailable()
- def test_qdisc_ets(self):
- copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
+ @expectedFailureIfModuleIsNotAvailable('sch_sfb')
+ def test_qdisc_sfb(self):
+ copy_network_unit('25-qdisc-sfb.network', '12-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
+ self.assertRegex(output, 'qdisc sfb 39: root')
+ self.assertRegex(output, 'limit 200000')
- self.assertRegex(output, 'qdisc ets 3a: root')
- self.assertRegex(output, 'bands 10 strict 3')
- self.assertRegex(output, 'quanta 1 2 3 4 5')
- self.assertRegex(output, 'priomap 3 4 5 6 7')
+ @expectedFailureIfModuleIsNotAvailable('sch_sfq')
+ def test_qdisc_sfq(self):
+ copy_network_unit('25-qdisc-sfq.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_online(['dummy98:routable'])
- @expectedFailureIfFQPIEIsNotAvailable()
- def test_qdisc_fq_pie(self):
- copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc sfq 36: root')
+ self.assertRegex(output, 'perturb 5sec')
+
+ @expectedFailureIfModuleIsNotAvailable('sch_tbf')
+ def test_qdisc_tbf(self):
+ copy_network_unit('25-qdisc-tbf.network', '12-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output('tc qdisc show dev dummy98')
print(output)
+ self.assertRegex(output, 'qdisc tbf 35: root')
+ self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
- self.assertRegex(output, 'qdisc fq_pie 3a: root')
- self.assertRegex(output, 'limit 200000p')
+ @expectedFailureIfModuleIsNotAvailable('sch_teql')
+ def test_qdisc_teql(self):
+ call_quiet('rmmod sch_teql')
+
+ copy_network_unit('25-qdisc-teql.network', '12-dummy.netdev')
+ start_networkd()
+ self.wait_links('dummy98')
+ check_output('modprobe sch_teql max_equalizers=2')
+ self.wait_online(['dummy98:routable'])
+
+ output = check_output('tc qdisc show dev dummy98')
+ print(output)
+ self.assertRegex(output, 'qdisc teql1 31: root')
+
+class NetworkWaitOnlineTests(unittest.TestCase, Utilities):
+
+ def setUp(self):
+ setup_common()
+
+ def tearDown(self):
+ tear_down_common()
+ @expectedFailureIfModuleIsNotAvailable('sch_netem')
def test_wait_online_ipv4(self):
copy_network_unit('25-veth.netdev', '25-dhcp-server-with-ipv6-prefix.network', '25-dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network')
start_networkd()
self.wait_address('veth99', r'192.168.5.[0-9]+', ipv='-4', timeout_sec=1)
+ @expectedFailureIfModuleIsNotAvailable('sch_netem')
def test_wait_online_ipv6(self):
copy_network_unit('25-veth.netdev', '25-ipv6-prefix-with-delay.network', '25-ipv6ra-prefix-client-with-static-ipv4-address.network')
start_networkd()
self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
- self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '1')
- self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '1')
+ self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
+ self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
def test_bridge_property(self):
copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
start_networkd()
self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
+ output = check_output('ip -d link show bridge99')
+ print(output)
+ self.assertIn('mtu 9000 ', output)
+
output = check_output('ip -d link show test1')
print(output)
- self.assertRegex(output, 'master')
- self.assertRegex(output, 'bridge')
+ self.assertIn('master bridge99 ', output)
+ self.assertIn('bridge_slave', output)
+ self.assertIn('mtu 9000 ', output)
output = check_output('ip -d link show dummy98')
print(output)
- self.assertRegex(output, 'master')
- self.assertRegex(output, 'bridge')
+ self.assertIn('master bridge99 ', output)
+ self.assertIn('bridge_slave', output)
+ self.assertIn('mtu 9000 ', output)
output = check_output('ip addr show bridge99')
print(output)
- self.assertRegex(output, '192.168.0.15/24')
+ self.assertIn('192.168.0.15/24', output)
output = check_output('bridge -d link show dummy98')
print(output)
self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
- self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '1')
- self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '1')
+ self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
+ self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
output = check_output('bridge -d link show test1')
print(output)
check_output('ip address add 192.168.0.16/24 dev bridge99')
output = check_output('ip addr show bridge99')
print(output)
- self.assertRegex(output, '192.168.0.16/24')
+ self.assertIn('192.168.0.16/24', output)
# for issue #6088
print('### ip -6 route list table all dev bridge99')
self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
remove_link('test1')
-
self.wait_operstate('bridge99', 'degraded-carrier')
- remove_link('dummy98')
+ output = check_output('ip -d link show bridge99')
+ print(output)
+ self.assertIn('mtu 9000 ', output)
+
+ output = check_output('ip -d link show dummy98')
+ print(output)
+ self.assertIn('master bridge99 ', output)
+ self.assertIn('bridge_slave', output)
+ self.assertIn('mtu 9000 ', output)
+ remove_link('dummy98')
self.wait_operstate('bridge99', 'no-carrier')
+ output = check_output('ip -d link show bridge99')
+ print(output)
+ # When no carrier, the kernel may reset the MTU
+ self.assertIn('NO-CARRIER', output)
+
output = check_output('ip address show bridge99')
print(output)
- self.assertRegex(output, 'NO-CARRIER')
- self.assertNotRegex(output, '192.168.0.15/24')
- self.assertRegex(output, '192.168.0.16/24') # foreign address is kept
+ self.assertNotIn('192.168.0.15/24', output)
+ self.assertIn('192.168.0.16/24', output) # foreign address is kept
print('### ip -6 route list table all dev bridge99')
output = check_output('ip -6 route list table all dev bridge99')
print(output)
self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
+ check_output('ip link add dummy98 type dummy')
+ self.wait_online(['dummy98:enslaved', 'bridge99:routable'])
+
+ output = check_output('ip -d link show bridge99')
+ print(output)
+ self.assertIn('mtu 9000 ', output)
+
+ output = check_output('ip -d link show dummy98')
+ print(output)
+ self.assertIn('master bridge99 ', output)
+ self.assertIn('bridge_slave', output)
+ self.assertIn('mtu 9000 ', output)
+
def test_bridge_configure_without_carrier(self):
copy_network_unit('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
'11-dummy.netdev')
f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
udev_reload()
- call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+ call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
output = check_output('ip link show dev eni99np1')
print(output)
f.write('[Link]\nSR-IOVVirtualFunctions=\n')
udev_reload()
- call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+ call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
output = check_output('ip link show dev eni99np1')
print(output)
f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
udev_reload()
- call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+ call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
output = check_output('ip link show dev eni99np1')
print(output)
f.write('[Link]\nSR-IOVVirtualFunctions=\n')
udev_reload()
- call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+ call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
output = check_output('ip link show dev eni99np1')
print(output)
self.verify_dhcp4_6rd(tunnel_name)
- print('Wait for the DHCP lease to be expired')
+ print('Wait for the DHCP lease to be renewed/rebind')
time.sleep(120)
self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
+ parser.add_argument('--timesyncd', help='Path to systemd-timesyncd', dest='timesyncd_bin')
parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
+ parser.add_argument('--udevadm', help='Path to udevadm', dest='udevadm_bin')
parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
ns, unknown_args = parser.parse_known_args(namespace=unittest)
if ns.build_dir:
- if ns.networkd_bin or ns.resolved_bin or ns.udevd_bin or ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin:
- print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
+ if ns.networkd_bin or ns.resolved_bin or ns.timesyncd_bin or ns.udevd_bin or \
+ ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin or ns.udevadm_bin:
+ print('WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.')
networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
+ timesyncd_bin = os.path.join(ns.build_dir, 'systemd-timesyncd')
udevd_bin = os.path.join(ns.build_dir, 'systemd-udevd')
wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
+ udevadm_bin = os.path.join(ns.build_dir, 'udevadm')
else:
if ns.networkd_bin:
networkd_bin = ns.networkd_bin
if ns.resolved_bin:
resolved_bin = ns.resolved_bin
+ if ns.timesyncd_bin:
+ timesyncd_bin = ns.timesyncd_bin
if ns.udevd_bin:
udevd_bin = ns.udevd_bin
if ns.wait_online_bin:
resolvectl_bin = ns.resolvectl_bin
if ns.timedatectl_bin:
timedatectl_bin = ns.timedatectl_bin
+ if ns.udevadm_bin:
+ udevadm_bin = ns.udevadm_bin
use_valgrind = ns.use_valgrind
enable_debug = ns.enable_debug
with_coverage = ns.with_coverage
if use_valgrind:
- networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
- resolvectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin]
- timedatectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin]
- wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
- else:
- networkctl_cmd = [networkctl_bin]
- resolvectl_cmd = [resolvectl_bin]
- timedatectl_cmd = [timedatectl_bin]
- wait_online_cmd = [wait_online_bin]
+ # Do not forget the trailing space.
+ valgrind_cmd = 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
+
+ networkctl_cmd = valgrind_cmd.split() + [networkctl_bin]
+ resolvectl_cmd = valgrind_cmd.split() + [resolvectl_bin]
+ timedatectl_cmd = valgrind_cmd.split() + [timedatectl_bin]
+ udevadm_cmd = valgrind_cmd.split() + [udevadm_bin]
+ wait_online_cmd = valgrind_cmd.split() + [wait_online_bin]
if asan_options:
env.update({'ASAN_OPTIONS': asan_options})
env.update({'LSAN_OPTIONS': lsan_options})
if ubsan_options:
env.update({'UBSAN_OPTIONS': ubsan_options})
+ if use_valgrind:
+ env.update({'SYSTEMD_MEMPOOL': '0'})
wait_online_env = env.copy()
if enable_debug:
# utility functions for shell tests
assert_true() {(
- local rc
-
set +ex
+ local rc
+
"$@"
rc=$?
if [[ $rc -ne 0 ]]; then
)}
assert_rc() {(
- local rc exp="${1?}"
-
set +ex
+ local rc exp="${1?}"
+
shift
"$@"
rc=$?
--- /dev/null
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+set -o pipefail
+
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
+wait_service_active() {(
+ set +ex
+ for (( i = 0; i < 20; i++ )); do
+ if (( i != 0 )); then sleep 0.5; fi
+ if systemctl --quiet is-active "${1?}"; then
+ return 0
+ fi
+ done
+ return 1
+)}
+
+wait_service_inactive() {(
+ set +ex
+ for (( i = 0; i < 20; i++ )); do
+ if (( i != 0 )); then sleep 0.5; fi
+ systemctl --quiet is-active "${1?}"
+ if [[ "$?" == "3" ]]; then
+ return 0
+ fi
+ done
+ return 1
+)}
+
+mkdir -p /run/systemd/system
+cat >/run/systemd/system/both.service <<EOF
+[Service]
+ExecStart=sleep 1000
+EOF
+
+cat >/run/systemd/system/on-add.service <<EOF
+[Service]
+ExecStart=sleep 1000
+EOF
+
+cat >/run/systemd/system/on-change.service <<EOF
+[Service]
+ExecStart=sleep 1000
+EOF
+
+systemctl daemon-reload
+
+mkdir -p /run/udev/rules.d/
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
+SUBSYSTEM=="net", KERNEL=="dummy9?", OPTIONS="log_level=debug"
+SUBSYSTEM=="net", KERNEL=="dummy9?", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="both.service", ENV{SYSTEMD_WANTS}+="on-add.service"
+SUBSYSTEM=="net", KERNEL=="dummy9?", ACTION=="change", TAG+="systemd", ENV{SYSTEMD_WANTS}+="both.service", ENV{SYSTEMD_WANTS}+="on-change.service"
+EOF
+
+udevadm control --reload
+
+# StopWhenUnneeded=no
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+systemctl stop both.service on-add.service
+
+udevadm trigger --action=change --settle /sys/class/net/dummy99
+udevadm info /sys/class/net/dummy99
+wait_service_active both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+wait_service_active on-change.service
+systemctl stop both.service on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+assert_rc 3 systemctl --quiet is-active both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+# StopWhenUnneeded=yes
+cat >/run/systemd/system/both.service <<EOF
+[Unit]
+StopWhenUnneeded=yes
+
+[Service]
+ExecStart=sleep 1000
+Type=simple
+EOF
+
+cat >/run/systemd/system/on-add.service <<EOF
+[Unit]
+StopWhenUnneeded=yes
+
+[Service]
+ExecStart=sleep 1000
+Type=simple
+EOF
+
+cat >/run/systemd/system/on-change.service <<EOF
+[Unit]
+StopWhenUnneeded=yes
+
+[Service]
+ExecStart=echo changed
+RemainAfterExit=true
+Type=oneshot
+EOF
+
+systemctl daemon-reload
+
+# StopWhenUnneeded=yes (single device, only add event)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+wait_service_inactive both.service
+wait_service_inactive on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+# StopWhenUnneeded=yes (single device, add and change event)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+udevadm trigger --action=change --settle /sys/class/net/dummy99
+assert_rc 0 systemctl --quiet is-active both.service
+wait_service_inactive on-add.service
+wait_service_active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+wait_service_inactive both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+wait_service_inactive on-change.service
+
+# StopWhenUnneeded=yes (multiple devices, only add events)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link add dummy98 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy98
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link del dummy98
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy98
+wait_service_inactive both.service
+wait_service_inactive on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+# StopWhenUnneeded=yes (multiple devices, add and change events)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link add dummy98 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy98
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+udevadm trigger --action=change --settle /sys/class/net/dummy99
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+wait_service_active on-change.service
+
+ip link del dummy98
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy98
+assert_rc 0 systemctl --quiet is-active both.service
+wait_service_inactive on-add.service
+assert_rc 0 systemctl --quiet is-active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+wait_service_inactive both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+wait_service_inactive on-change.service
+
+# cleanup
+rm -f /run/udev/rules.d/50-testsuite.rules
+udevadm control --reload
+
+rm -f /run/systemd/system/on-add.service
+rm -f /run/systemd/system/on-change.service
+systemctl daemon-reload
+
+exit 0
RemainAfterExit=yes
MountAPIVFS=yes
PrivateTmp=yes
-ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do sleep 0.1; done; mount | grep -F "/dev/mapper/${roothash}-verity" | grep -q -F "nosuid"'
+ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do sleep 0.1; done; mount | grep -e "/dev/mapper/${roothash}-verity" -e "/dev/mapper/loop[0-9]*-verity" | grep -q -F "nosuid"'
EOF
systemctl start testservice-50d.service
systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
+systemd-run -P --property ExtensionImages=/usr/share/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
cat >/run/systemd/system/testservice-50e.service <<EOF
[Service]
MountAPIVFS=yes
systemctl is-active testservice-50e.service
# ExtensionDirectories will set up an overlay
-mkdir -p "${image_dir}/app0" "${image_dir}/app1"
+mkdir -p "${image_dir}/app0" "${image_dir}/app1" "${image_dir}/app-nodistro"
systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
systemd-dissect --mount /usr/share/app0.raw "${image_dir}/app0"
systemd-dissect --mount /usr/share/app1.raw "${image_dir}/app1"
+systemd-dissect --mount /usr/share/app-nodistro.raw "${image_dir}/app-nodistro"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
+systemd-run -P --property ExtensionDirectories="${image_dir}/app-nodistro" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
cat >/run/systemd/system/testservice-50f.service <<EOF
[Service]
MountAPIVFS=yes
systemd-dissect --umount "${image_dir}/app0"
systemd-dissect --umount "${image_dir}/app1"
+# Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence
+mkdir -p /var/lib/extensions/
+ln -s /usr/share/app-nodistro.raw /var/lib/extensions/app-nodistro.raw
+systemd-sysext merge
+grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
+systemd-sysext unmerge
+mkdir -p /etc/extensions/app-nodistro
+systemd-sysext merge
+test ! -e /usr/lib/systemd/system/some_file
+systemd-sysext unmerge
+rmdir /etc/extensions/app-nodistro
+rm /var/lib/extensions/app-nodistro.raw
+
echo OK >/testok
exit 0
: >/failed
+# Run a timer for every 15 minutes before setting the current time
+systemd-run --unit test-timer-1 --on-calendar "*:0/15:0" true
+
# Reset host date to current time, 3 days in the past.
date -s "-3 days"
-# Run a timer for every 15 minutes.
-systemd-run --unit test-timer --on-calendar "*:0/15:0" true
+# Run another timer for every 15 minutes, after setting the time
+systemd-run --unit test-timer-2 --on-calendar "*:0/15:0" true
+
+next_elapsed_t1=$(systemctl show test-timer-1.timer -p NextElapseUSecRealtime --value)
+next_elapsed_t1=$(date -d "${next_elapsed_t1}" +%s)
+now=$(date +%s)
+time_delta_t1=$((next_elapsed_t1 - now))
-next_elapsed=$(systemctl show test-timer.timer -p NextElapseUSecRealtime --value)
-next_elapsed=$(date -d "${next_elapsed}" +%s)
+next_elapsed_t2=$(systemctl show test-timer-2.timer -p NextElapseUSecRealtime --value)
+next_elapsed_t2=$(date -d "${next_elapsed_t2}" +%s)
now=$(date +%s)
-time_delta=$((next_elapsed - now))
+time_delta_t2=$((next_elapsed_t2 - now))
+
+# Check that the timer will elapse in less than 20 minutes.
+((0 < time_delta_t1 && time_delta_t1 < 1200)) || {
+ echo 'Timer elapse outside of the expected 20 minute window.'
+ echo " next_elapsed_t1=${next_elapsed_t1}"
+ echo " now=${now}"
+ echo " time_delta_t1=${time_delta_t1}"
+ echo ''
+} >>/failed_t1
# Check that the timer will elapse in less than 20 minutes.
-((0 < time_delta && time_delta < 1200)) || {
+((0 < time_delta_t2 && time_delta_t2 < 1200)) || {
echo 'Timer elapse outside of the expected 20 minute window.'
- echo " next_elapsed=${next_elapsed}"
+ echo " next_elapsed_t2=${next_elapsed_t2}"
echo " now=${now}"
- echo " time_delta=${time_delta}"
+ echo " time_delta_t2=${time_delta_t2}"
echo ''
-} >>/failed
+} >>/failed_t2
-if test ! -s /failed ; then
- rm -f /failed
+if test ! -s /failed_t1 && test ! -s /failed_t2; then
+ rm -f /failed_t*
touch /testok
fi
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -ex
+set -o pipefail
export SYSTEMD_LOG_LEVEL=debug
echo -n passphrase >/tmp/passphrase
cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom $img /tmp/passphrase
+# Unlocking via keyfile
+systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto $img
+
# Enroll unlock with default PCR policy
env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img
/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1
# Check failure with wrong PIN
env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
+# Check LUKS2 token plugin unlock (i.e. without specifying tpm2-device=auto)
+if cryptsetup --help | grep -q 'LUKS2 external token plugin support is compiled-in'; then
+ env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1
+ /usr/lib/systemd/systemd-cryptsetup detach test-volume
+
+ # Check failure with wrong PIN
+ env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1 && { echo 'unexpected success'; exit 1; }
+else
+ echo 'cryptsetup has no LUKS2 token plugin support, skipping'
+fi
+
# Check failure with wrong PCR (and correct PIN)
tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000
env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000
/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && exit 1
-if [[ -e /usr/lib/systemd/sytemd-measure ]]; then
+if [[ -e /usr/lib/systemd/systemd-measure ]]; then
echo HALLO > /tmp/tpmdata1
echo foobar > /tmp/tpmdata2
cat >/tmp/result <<EOF
- 11:sha1=5177e4ad69db92192c10e5f80402bf81bfec8a81
- 11:sha256=37b48bd0b222394dbe3cceff2fca4660c4b0a90ae9369ec90b42f14489989c13
- 11:sha384=5573f9b2caf55b1d0a6a701f890662d682af961899f0419cf1e2d5ea4a6a68c1f25bd4f5b8a0865eeee82af90f5cb087
- 11:sha512=961305d7e9981d6606d1ce97b3a9a1f92610cac033e9c39064895f0e306abc1680463d55767bd98e751eae115bdef3675a9ee1d29ed37da7885b1db45bb2555b
+11:sha1=5177e4ad69db92192c10e5f80402bf81bfec8a81
+11:sha256=37b48bd0b222394dbe3cceff2fca4660c4b0a90ae9369ec90b42f14489989c13
+11:sha384=5573f9b2caf55b1d0a6a701f890662d682af961899f0419cf1e2d5ea4a6a68c1f25bd4f5b8a0865eeee82af90f5cb087
+11:sha512=961305d7e9981d6606d1ce97b3a9a1f92610cac033e9c39064895f0e306abc1680463d55767bd98e751eae115bdef3675a9ee1d29ed37da7885b1db45bb2555b
EOF
- /usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 | cmp - /tmp/result
+ /usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 | cmp - /tmp/result
else
echo "/usr/lib/systemd/systemd-measure not found, skipping the test case"
fi
set -eux
set -o pipefail
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
export SYSTEMD_LOG_LEVEL=debug
-echo "foo.bar=42" > /etc/sysctl.d/foo.conf
-[[ $(/usr/lib/systemd/systemd-sysctl /etc/sysctl.d/foo.conf)$? -eq 0 ]]
-[[ $(/usr/lib/systemd/systemd-sysctl --strict /etc/sysctl.d/foo.conf)$? -ne 0 ]]
+echo "foo.bar=42" > /tmp/foo.conf
+assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf
+assert_rc 1 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf
+
+echo "-foo.foo=42" > /tmp/foo.conf
+assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf
+assert_rc 0 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf
+
+if ! systemd-detect-virt --quiet --container; then
+ ip link add hoge type dummy
+ udevadm wait /sys/class/net/hoge
+
+ cat >/tmp/foo.conf <<EOF
+net.ipv4.conf.*.drop_gratuitous_arp=1
+net.ipv4.*.*.bootp_relay=1
+net.ipv4.aaa.*.disable_policy=1
+EOF
+
+ echo 0 > /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp
+ echo 0 > /proc/sys/net/ipv4/conf/hoge/bootp_relay
+ echo 0 > /proc/sys/net/ipv4/conf/hoge/disable_policy
-echo "-foo.foo=42" > /etc/sysctl.d/foo.conf
-[[ $(/usr/lib/systemd/systemd-sysctl /etc/sysctl.d/foo.conf)$? -eq 0 ]]
-[[ $(/usr/lib/systemd/systemd-sysctl --strict /etc/sysctl.d/foo.conf)$? -eq 0 ]]
+ assert_rc 0 /usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge /tmp/foo.conf
+ assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp)" "1"
+ assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/bootp_relay)" "1"
+ assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/disable_policy)" "0"
+fi
touch /testok
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
-# The official unmodified version of the script can be found at
-# https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh
+set -eux
-set -e
+COVERITY_SCAN_TOOL_BASE="/tmp/coverity-scan-analysis"
+COVERITY_SCAN_PROJECT_NAME="systemd/systemd"
-# Declare build command
-COVERITY_SCAN_BUILD_COMMAND="ninja -C cov-build"
+function coverity_install_script {
+ local platform tool_url tool_archive
-# Environment check
-# Use default values if not set
-SCAN_URL=${SCAN_URL:="https://scan.coverity.com"}
-TOOL_BASE=${TOOL_BASE:="/tmp/coverity-scan-analysis"}
-UPLOAD_URL=${UPLOAD_URL:="https://scan.coverity.com/builds"}
+ platform=$(uname)
+ tool_url="https://scan.coverity.com/download/${platform}"
+ tool_archive="/tmp/cov-analysis-${platform}.tgz"
-# These must be set by environment
-echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are available on Project Settings page on scan.coverity.com\033[0m"
-[ -z "$COVERITY_SCAN_PROJECT_NAME" ] && echo "ERROR: COVERITY_SCAN_PROJECT_NAME must be set" && exit 1
-[ -z "$COVERITY_SCAN_NOTIFICATION_EMAIL" ] && echo "ERROR: COVERITY_SCAN_NOTIFICATION_EMAIL must be set" && exit 1
-[ -z "$COVERITY_SCAN_BRANCH_PATTERN" ] && echo "ERROR: COVERITY_SCAN_BRANCH_PATTERN must be set" && exit 1
-[ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1
-[ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1
+ set +x # this is supposed to hide COVERITY_SCAN_TOKEN
+ echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
+ wget -nv -O "$tool_archive" "$tool_url" --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=${COVERITY_SCAN_TOKEN:?}"
+ set -x
-# Verify this branch should run
-if [[ "${CURRENT_REF^^}" =~ "${COVERITY_SCAN_BRANCH_PATTERN^^}" ]]; then
- echo -e "\033[33;1mCoverity Scan configured to run on branch ${CURRENT_REF}\033[0m"
-else
- echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${CURRENT_REF}\033[0m"
- exit 1
-fi
-
-# Verify upload is permitted
-AUTH_RES=`curl -s --form project="$COVERITY_SCAN_PROJECT_NAME" --form token="$COVERITY_SCAN_TOKEN" $SCAN_URL/api/upload_permitted`
-if [ "$AUTH_RES" = "Access denied" ]; then
- echo -e "\033[33;1mCoverity Scan API access denied. Check COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN.\033[0m"
- exit 1
-else
- AUTH=`echo $AUTH_RES | jq .upload_permitted`
- if [ "$AUTH" = "true" ]; then
- echo -e "\033[33;1mCoverity Scan analysis authorized per quota.\033[0m"
- else
- WHEN=`echo $AUTH_RES | jq .next_upload_permitted_at`
- echo -e "\033[33;1mCoverity Scan analysis NOT authorized until $WHEN.\033[0m"
- exit 1
- fi
-fi
-
-TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
-export PATH="$TOOL_DIR/bin:$PATH"
-
-# Disable CCACHE for cov-build to compilation units correctly
-export CCACHE_DISABLE=1
-
-# FUNCTION DEFINITIONS
-# --------------------
-_help()
-{
- # displays help and exits
- cat <<-EOF
- USAGE: $0 [CMD] [OPTIONS]
-
- CMD
- build Issue Coverity build
- upload Upload coverity archive for analysis
- Note: By default, archive is created from default results directory.
- To provide custom archive or results directory, see --result-dir
- and --tar options below.
-
- OPTIONS
- -h,--help Display this menu and exits
-
- Applicable to build command
- ---------------------------
- -o,--out-dir Specify Coverity intermediate directory (defaults to 'cov-int')
- -t,--tar bool, archive the output to .tgz file (defaults to false)
-
- Applicable to upload command
- ----------------------------
- -d, --result-dir Specify result directory if different from default ('cov-int')
- -t, --tar ARCHIVE Use custom .tgz archive instead of intermediate directory or pre-archived .tgz
- (by default 'analysis-result.tgz'
- EOF
- return;
-}
-
-_pack()
-{
- RESULTS_ARCHIVE=${RESULTS_ARCHIVE:-'analysis-results.tgz'}
-
- echo -e "\033[33;1mTarring Coverity Scan Analysis results...\033[0m"
- tar czf $RESULTS_ARCHIVE $RESULTS_DIR
- SHA=`git rev-parse --short HEAD`
-
- PACKED=true
+ mkdir -p "$COVERITY_SCAN_TOOL_BASE"
+ pushd "$COVERITY_SCAN_TOOL_BASE"
+ tar xzf "$tool_archive"
+ popd
}
+function run_coverity {
+ local results_dir tool_dir results_archive sha response status_code
-_build()
-{
- echo -e "\033[33;1mRunning Coverity Scan Analysis Tool...\033[0m"
- local _cov_build_options=""
- #local _cov_build_options="--return-emit-failures 8 --parse-error-threshold 85"
- eval "${COVERITY_SCAN_BUILD_COMMAND_PREPEND}"
- COVERITY_UNSUPPORTED=1 cov-build --dir $RESULTS_DIR $_cov_build_options sh -c "$COVERITY_SCAN_BUILD_COMMAND"
- cov-import-scm --dir $RESULTS_DIR --scm git --log $RESULTS_DIR/scm_log.txt
+ results_dir="cov-int"
+ tool_dir=$(find "$COVERITY_SCAN_TOOL_BASE" -type d -name 'cov-analysis*')
+ results_archive="analysis-results.tgz"
+ sha=$(git rev-parse --short HEAD)
- if [ $? != 0 ]; then
- echo -e "\033[33;1mCoverity Scan Build failed: $TEXT.\033[0m"
- return 1
- fi
-
- [ -z $TAR ] || [ $TAR = false ] && return 0
+ meson -Dman=false build
+ COVERITY_UNSUPPORTED=1 "$tool_dir/bin/cov-build" --dir "$results_dir" sh -c "ninja -C ./build -v"
+ "$tool_dir/bin/cov-import-scm" --dir "$results_dir" --scm git --log "$results_dir/scm_log.txt"
- if [ "$TAR" = true ]; then
- _pack
- fi
-}
+ tar czf "$results_archive" "$results_dir"
-
-_upload()
-{
- # pack results
- [ -z $PACKED ] || [ $PACKED = false ] && _pack
-
- # Upload results
+ set +x # this is supposed to hide COVERITY_SCAN_TOKEN
echo -e "\033[33;1mUploading Coverity Scan Analysis results...\033[0m"
response=$(curl \
- --silent --write-out "\n%{http_code}\n" \
- --form project=$COVERITY_SCAN_PROJECT_NAME \
- --form token=$COVERITY_SCAN_TOKEN \
- --form email=$COVERITY_SCAN_NOTIFICATION_EMAIL \
- --form file=@$RESULTS_ARCHIVE \
- --form version=$SHA \
- --form description="Travis CI build" \
- $UPLOAD_URL)
+ --silent --write-out "\n%{http_code}\n" \
+ --form project="$COVERITY_SCAN_PROJECT_NAME" \
+ --form token="${COVERITY_SCAN_TOKEN:?}" \
+ --form email="${COVERITY_SCAN_NOTIFICATION_EMAIL:?}" \
+ --form file="@$results_archive" \
+ --form version="$sha" \
+ --form description="Daily build" \
+ https://scan.coverity.com/builds)
printf "\033[33;1mThe response is\033[0m\n%s\n" "$response"
status_code=$(echo "$response" | sed -n '$p')
- # Coverity Scan used to respond with 201 on successfully receiving analysis results.
- # Now for some reason it sends 200 and may change back in the foreseeable future.
- # See https://github.com/pmem/pmdk/commit/7b103fd2dd54b2e5974f71fb65c81ab3713c12c5
if [ "$status_code" != "200" ]; then
- TEXT=$(echo "$response" | sed '$d')
- echo -e "\033[33;1mCoverity Scan upload failed: $TEXT.\033[0m"
- exit 1
+ echo -e "\033[33;1mCoverity Scan upload failed: $(echo "$response" | sed '$d').\033[0m"
+ return 1
fi
-
- echo -e "\n\033[33;1mCoverity Scan Analysis completed successfully.\033[0m"
- exit 0
+ set -x
}
-# PARSE COMMAND LINE OPTIONS
-# --------------------------
-
-case $1 in
- -h|--help)
- _help
- exit 0
- ;;
- build)
- CMD='build'
- TEMP=`getopt -o ho:t --long help,out-dir:,tar -n '$0' -- "$@"`
- _ec=$?
- [[ $_ec -gt 0 ]] && _help && exit $_ec
- shift
- ;;
- upload)
- CMD='upload'
- TEMP=`getopt -o hd:t: --long help,result-dir:tar: -n '$0' -- "$@"`
- _ec=$?
- [[ $_ec -gt 0 ]] && _help && exit $_ec
- shift
- ;;
- *)
- _help && exit 1 ;;
-esac
-
-RESULTS_DIR='cov-int'
-
-eval set -- "$TEMP"
-if [ $? != 0 ] ; then exit 1 ; fi
-
-# extract options and their arguments into variables.
-if [[ $CMD == 'build' ]]; then
- TAR=false
- while true ; do
- case $1 in
- -h|--help)
- _help
- exit 0
- ;;
- -o|--out-dir)
- RESULTS_DIR="$2"
- shift 2
- ;;
- -t|--tar)
- TAR=true
- shift
- ;;
- --) _build; shift ; break ;;
- *) echo "Internal error" ; _help && exit 6 ;;
- esac
- done
-
-elif [[ $CMD == 'upload' ]]; then
- while true ; do
- case $1 in
- -h|--help)
- _help
- exit 0
- ;;
- -d|--result-dir)
- CHANGE_DEFAULT_DIR=true
- RESULTS_DIR="$2"
- shift 2
- ;;
- -t|--tar)
- RESULTS_ARCHIVE="$2"
- [ -z $CHANGE_DEFAULT_DIR ] || [ $CHANGE_DEFAULT_DIR = false ] && PACKED=true
- shift 2
- ;;
- --) _upload; shift ; break ;;
- *) echo "Internal error" ; _help && exit 6 ;;
- esac
- done
-
-fi
+coverity_install_script
+run_coverity
+++ /dev/null
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-# Download and extract coverity tool
-
-set -e
-set -o pipefail
-
-# Environment check
-if [ -z "$COVERITY_SCAN_TOKEN" ]; then
- echo >&2 'ERROR: COVERITY_SCAN_TOKEN must be set'
- exit 1
-fi
-
-# Use default values if not set
-PLATFORM="$(uname)"
-TOOL_BASE="${TOOL_BASE:-/tmp/coverity-scan-analysis}"
-TOOL_ARCHIVE="${TOOL_ARCHIVE:-/tmp/cov-analysis-${PLATFORM}.tgz}"
-TOOL_URL="https://scan.coverity.com/download/${PLATFORM}"
-
-# Make sure wget is installed
-sudo apt-get update && sudo apt-get -y install wget
-
-# Get coverity tool
-if [ ! -d "$TOOL_BASE" ]; then
- # Download Coverity Scan Analysis Tool
- if [ ! -e "$TOOL_ARCHIVE" ]; then
- echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
- wget -nv -O "$TOOL_ARCHIVE" "$TOOL_URL" --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=$COVERITY_SCAN_TOKEN"
- fi
-
- # Extract Coverity Scan Analysis Tool
- echo -e "\033[33;1mExtracting Coverity Scan Analysis Tool...\033[0m"
- mkdir -p "$TOOL_BASE"
- pushd "$TOOL_BASE"
- tar xzf "$TOOL_ARCHIVE"
- popd
-fi
-
-echo -e "\033[33;1mCoverity Scan Analysis Tool can be found at $TOOL_BASE ...\033[0m"
+++ /dev/null
-# SPDX-License-Identifier: LGPL-2.1-or-later
-#
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-[Unit]
-Description=Reload Configuration from the Real Root
-DefaultDependencies=no
-Requires=initrd-root-fs.target
-After=initrd-root-fs.target
-OnFailure=emergency.target
-OnFailureJobMode=replace-irreversibly
-AssertPathExists=/etc/initrd-release
-
-[Service]
-Type=oneshot
-ExecStartPre=-systemctl daemon-reload
-# we have to retrigger initrd-fs.target after daemon-reload
-ExecStart=-systemctl --no-block start initrd-fs.target
-ExecStart=systemctl --no-block start initrd-cleanup.service
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Mountpoints Configured in the Real Root
+AssertPathExists=/etc/initrd-release
+
+DefaultDependencies=no
+Requires=initrd-root-fs.target
+After=initrd-root-fs.target
+
+OnFailure=emergency.target
+OnFailureJobMode=replace-irreversibly
+
+[Service]
+Type=oneshot
+
+# FIXME: once dracut is patched to install the symlink, change to:
+# ExecStart={{ROOTLIBEXECDIR}}/systemd-sysroot-fstab-check
+ExecStart=@{{SYSTEM_GENERATOR_DIR}}/systemd-fstab-generator systemd-sysroot-fstab-check
+
+# We want to enqueue initrd-cleanup.service/start after we finished the part
+# above. It can't be part of the initial transaction, because non-oneshot units
+# use Conflicts=initrd-cleanup.service to be terminated before we switch root.
+# Effectively, initrd-parse-etc.service acts as a synchronization point after
+# which cleanup of the initrd processes starts.
+ExecStart=systemctl --no-block start initrd-cleanup.service
['suspend-then-hibernate.target', 'ENABLE_HIBERNATE'],
['initrd-cleanup.service', 'ENABLE_INITRD'],
['initrd-fs.target', 'ENABLE_INITRD'],
- ['initrd-parse-etc.service', 'ENABLE_INITRD'],
['initrd-root-device.target', 'ENABLE_INITRD'],
['initrd-root-fs.target', 'ENABLE_INITRD'],
['initrd-switch-root.service', 'ENABLE_INITRD'],
['emergency.service', ''],
['getty@.service', '',
'autovt@.service'],
+ ['initrd-parse-etc.service', 'ENABLE_INITRD'],
['kmod-static-nodes.service', 'HAVE_KMOD ENABLE_TMPFILES',
'sysinit.target.wants/'],
['quotaon.service', 'ENABLE_QUOTACHECK'],
DeviceAllow=char-* rw
ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
ExecReload=networkctl reload
+FileDescriptorStoreMax=512
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes