]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #24263 from pothos/sysext-for-static-binaries
authorLennart Poettering <lennart@poettering.net>
Mon, 15 Aug 2022 11:34:54 +0000 (13:34 +0200)
committerGitHub <noreply@github.com>
Mon, 15 Aug 2022 11:34:54 +0000 (13:34 +0200)
sysext: Support distribution-independent extensions with static binaries

104 files changed:
.github/advanced-issue-labeler.yml
.github/workflows/coverity.yml
.github/workflows/linter.yml
.gitignore
.semaphore/semaphore-runner.sh
NEWS
TODO
docs/CREDENTIALS.md
hwdb.d/60-sensor.hwdb
hwdb.d/70-analyzers.hwdb
man/org.freedesktop.oom1.xml
man/systemd-cryptenroll.xml
man/systemd.net-naming-scheme.xml
man/systemd.resource-control.xml
meson.build
mkosi.default.d/10-systemd.conf
po/hu.po
rules.d/70-uaccess.rules.in
src/basic/cgroup-util.h
src/boot/efi/boot.c
src/boot/efi/meson.build
src/boot/efi/stub.c
src/core/cgroup.c
src/core/dbus-cgroup.c
src/core/device.c
src/core/load-fragment-gperf.gperf.in
src/core/load-fragment.c
src/core/load-fragment.h
src/core/main.c
src/core/scope.c
src/core/scope.h
src/core/unit.c
src/cryptenroll/cryptenroll.c
src/firstboot/firstboot.c
src/journal/journald-server.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-monitor.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-sd-device-monitor.c
src/libsystemd/sd-device/test-sd-device.c
src/login/pam_systemd.c
src/network/netdev/netdev.c
src/network/networkd-dhcp-common.c
src/network/networkd-manager.c
src/network/networkd-network.c
src/network/networkd-setlink.c
src/network/networkd-sriov.c
src/network/tc/qdisc.c
src/network/tc/qdisc.h
src/network/tc/teql.c
src/oom/oomd-manager-bus.c
src/oom/oomd-manager.c
src/partition/repart.c
src/partition/test-repart.sh
src/resolve/resolvectl.c
src/resolve/resolved-dnssd.c
src/shared/bus-locator.c
src/shared/bus-locator.h
src/shared/bus-print-properties.c
src/shared/bus-unit-util.c
src/shared/cgroup-setup.c
src/shared/cgroup-setup.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/shared/creds-util.c
src/shared/creds-util.h
src/shared/netif-naming-scheme.c
src/shared/netif-naming-scheme.h
src/shared/sleep-config.c
src/shared/sleep-config.h
src/shared/tpm2-util.c
src/shared/user-record-show.c
src/sleep/sleep.c
src/systemd/sd-device.h
src/sysusers/sysusers.c
src/udev/cdrom_id/cdrom_id.c
src/udev/net/link-config.c
src/udev/udev-builtin-net_id.c
src/udev/udevd.c
test/networkd-test.py
test/test-network/conf/25-qdisc-clsact-and-htb.network [deleted file]
test/test-network/conf/25-qdisc-clsact.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-codel.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-fq.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-fq_codel.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-gred.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-htb-fifo.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-ingress.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-netem-compat.network [moved from test/test-network/conf/25-qdisc-ingress-netem-compat.network with 84% similarity]
test/test-network/conf/25-qdisc-netem.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-qfq.network
test/test-network/conf/25-qdisc-sfb.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-sfq.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-tbf.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-teql.network [new file with mode: 0644]
test/test-network/conf/25-tap.netdev
test/test-network/conf/25-tun.netdev
test/test-network/systemd-networkd-tests.py
test/units/assert.sh
test/units/testsuite-17.07.sh [new file with mode: 0755]
test/units/testsuite-70.sh
tools/coverity.sh
tools/get-coverity.sh [deleted file]

index 87ac69dc6c1f1524f330193241f803a29e714abb..3ab23935471c2cd4f4cd264ba5c1c4b2b2373493 100644 (file)
@@ -34,7 +34,7 @@ policy:
   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']
index 904a6895fd4c64f2a2923746155f10fba0457c26..3fbebc6bbf1d0ce852247f9febfd3260330f02f0 100644 (file)
@@ -17,27 +17,14 @@ jobs:
     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
index 0612a709ce3c1c3c9bf0b749f9f110e86828356a..4c6a8d5e5a0ba873eefb434e94c28f2ebea6a1b0 100644 (file)
@@ -38,8 +38,7 @@ jobs:
           #              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
index 7b6d0a376e976ada9d7b8ba250b4e472c6dd1a07..8aa363eac4cfbafb69077282dd0e9e0f703fafcd 100644 (file)
@@ -37,3 +37,4 @@ __pycache__/
 /mkosi.default.d/**/*local*.conf
 /tags
 .dir-locals-2.el
+.vscode/
index ba2181171814485369761bfc6b6d28845a4f90c1..98fd7b441121d9d27903fe39d3e9a48ff7c0954d 100755 (executable)
@@ -19,14 +19,7 @@ PHASES=(${@:-SETUP RUN})
 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"
@@ -107,10 +100,10 @@ EOF
             # 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 ]
         ;;
         *)
diff --git a/NEWS b/NEWS
index 503777e42c8593b60f05e314d7ad7da9e564739d..f2747b6acab1a877cfdf06dbc14d67ff34be5ca0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,6 @@
 systemd System and Service Manager
 
-CHANGES WITH 252:
+CHANGES WITH 252 in spe:
 
         Announcement of Future Feature Removal
 
@@ -10,6 +10,153 @@ CHANGES WITH 252:
           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:
diff --git a/TODO b/TODO
index 23092799e2d279701daa1f00527dacf4decb14ce..1d155910d0bdd038312ae4e1458c6cb69dbf7575 100644 (file)
--- a/TODO
+++ b/TODO
@@ -117,6 +117,12 @@ Features:
   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.
index 4ba37844696e4e3dd439bcfb5e757b00ea41fd91..f0d9865829f4b30c4e56739384d5c069d8e2a5c4 100644 (file)
@@ -266,7 +266,8 @@ services where they are ultimately consumed.
    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
index 1c3f6b62bb1cabb7a53dd576597b1070ef74ebf7..7978675943c63bca5a980031070a1dec42246314 100644 (file)
@@ -406,27 +406,13 @@ sensor:modalias:acpi:KXCJ9000*:dmi:*:bvrZY-8-BI-PX4S70VTR400-X423B-005-D:*:rvnAM
 #########################################
 # 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*:*
- 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*:*
+# 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:*
  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*:*
+sensor:modalias:platform:cros-ec-accel-legacy:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
 #########################################
index 0a1911507a22e608e5d53f4bb1372200825195df..821ebcb1ca2f30a43b6b4fb7db0d7fb941f2ef60 100644 (file)
@@ -1,13 +1,21 @@
 # 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
 ###########################################################
index 838eb6738d8d3645b5dec24d5fa8a55069513e20..c6b8c7fb3d65fea3d156e370cfbc149d0f129c75 100644 (file)
@@ -39,6 +39,9 @@ node /org/freedesktop/oom1 {
   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 { ... };
@@ -56,12 +59,38 @@ node /org/freedesktop/oom1 {
 
     <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>
 
index 2aa396e3004bfe4790b5b166b0063e512e334d06..afde0fad7e2575e6fe6d3bd17983b017e0e4b992 100644 (file)
         </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>
 
index e5a3d7a3139dad6bf7bb888f2435ee820d2fadff..3d5b3326b148a3c02c91477d1b45dfe23a305a95 100644 (file)
     <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 fiemware 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
index 2b545e4d9316f97d07936b6293d27a637b223647..c16eb3951a18cf806562415397c492d29af21443 100644 (file)
         <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
index cf3aa2b4964976493e86a5985a7602d57467df19..a7e3e8774438a7aa288701cbeabb997e97ef0b98 100644 (file)
@@ -393,7 +393,7 @@ possible_common_cc_flags = [
 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
 
index 58b84cae98b814f8d6366bd0cf770e1b0c804f84..8efd1e97fa3265c1599fb2b5936e531671089c75 100644 (file)
@@ -8,11 +8,11 @@ Bootable=yes
 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]
index 5044f4ded1ec809cc9d9c4626824819ef6a1e0e1..c6b4acd7ac682aae9568333fbece274ad2335326 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -5,19 +5,21 @@
 #
 # 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"
@@ -71,73 +73,57 @@ msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
 
 #: 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"
@@ -165,45 +151,43 @@ msgstr "Gépinformációk beállítása"
 
 #: 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."
@@ -211,7 +195,7 @@ msgstr "Hitelesítés szükséges a rendszer területi beállításainak megadá
 
 #: 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."
@@ -220,7 +204,7 @@ msgstr ""
 
 #: 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 ""
@@ -231,7 +215,7 @@ msgstr ""
 
 #: 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."
@@ -241,7 +225,7 @@ msgstr ""
 
 #: 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."
@@ -250,7 +234,7 @@ msgstr ""
 
 #: 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."
@@ -260,7 +244,7 @@ msgstr ""
 
 #: 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 ""
@@ -273,7 +257,7 @@ msgstr ""
 #: 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 ""
@@ -286,7 +270,7 @@ msgstr ""
 #: 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 ""
@@ -299,7 +283,7 @@ msgstr ""
 #: 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 ""
@@ -311,7 +295,8 @@ msgstr ""
 
 #: 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 ""
@@ -322,22 +307,16 @@ msgstr ""
 "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
@@ -347,8 +326,8 @@ msgstr "Programfuttatás engedélyezése be nem jelentkezett felhasználó szám
 #: 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"
@@ -357,18 +336,18 @@ msgstr "Programfuttatás engedélyezése be nem jelentkezett felhasználók szá
 #: 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"
@@ -424,7 +403,7 @@ msgstr "Hitelesítés szükséges a rendszer újraindításához."
 
 #: 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 ""
@@ -448,52 +427,36 @@ msgstr ""
 "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"
@@ -539,7 +502,7 @@ msgstr "Hitelesítés szükséges a rendszer hibernálásához."
 
 #: 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 ""
@@ -582,59 +545,55 @@ msgstr ""
 
 #: 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"
@@ -646,13 +605,11 @@ msgstr "Hitelesítés szükséges a falüzenet beállításához"
 
 #: 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"
@@ -660,7 +617,7 @@ msgstr "Bejelentkezés helyi konténerbe"
 
 #: 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"
@@ -668,7 +625,7 @@ msgstr "Bejelentkezés a helyi gépre"
 
 #: 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"
@@ -714,246 +671,210 @@ msgstr "Hitelesítés szükséges helyi virtuális gépek és konténerek kezel
 
 #: 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"
@@ -1010,13 +931,12 @@ msgid "Authentication is required to restart '$(unit)'."
 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)'."
@@ -1030,24 +950,18 @@ msgstr ""
 "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)'."
index a3301be1bc8ffa0f43cb92ea38ca8128196d0302..b82ce04a39d384706a0662b50cc42b77adceb62f 100644 (file)
@@ -83,6 +83,7 @@ ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess"
 
 # 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"
index 4c413a8d174cc50ed96bb5a04c9c9ff8ec8793d3..df6d5b7bbb423ee9612dc19ab5df0666ea6e1d66 100644 (file)
@@ -86,6 +86,7 @@ bool cpu_accounting_is_cheap(void);
 
 /* 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)
index 87771c477dd6c669667247f28ad99a39bdbad8be..9c1d95e67256d43f1dcfb8e536dd54e32863e993 100644 (file)
@@ -2495,7 +2495,7 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir)
                 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);
         }
index 127b4e17a3a722c6ef90a95d8c732a8053f30e5d..95785dfd5d83d41895079a7f38b24b1a7877533f 100644 (file)
@@ -266,11 +266,19 @@ efi_ldflags = [
         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']
index 49ece4196196a94160d1bf4d72fbf5ee34231e52..003ae8c99a0bc192bac180a50282093e4f98d7b0 100644 (file)
@@ -239,7 +239,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         }
 
         /* 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 &&
index 8b389346150ccf1394578bff833f617ba3a0de90..8ecbd69031b80eed3877830162f79973382bdae0 100644 (file)
@@ -949,10 +949,25 @@ static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t qu
 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];
 
@@ -993,6 +1008,10 @@ static uint64_t cgroup_cpu_shares_to_weight(uint64_t shares) {
 }
 
 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);
 }
@@ -1398,6 +1417,7 @@ static void cgroup_context_apply(
                         } 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);
 
index 4fc4fb0021612b1604e1059902a25a8d747bc6a2..015dc238d682f16b33af5b060b6184484cb24565 100644 (file)
@@ -894,7 +894,6 @@ static int bus_cgroup_set_boolean(
         }
 
 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);
@@ -903,6 +902,35 @@ BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memo
 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,
index c18a40a494a8dc080a09312fcd5f7cc6219e134d..d6710262a99360f2ec31ebbaefdffe6eb1e4268b 100644 (file)
@@ -547,18 +547,24 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) {
         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)
index 54c1c0bb56bfe81d4770da5ac3c99c551dd92944..7675b7bb2e74619f59f0db8b52beadc1a436d097 100644 (file)
 {{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)
index d16c7b1df2b6919b9c71b5774700d4592c8ba975..0a2d4d4035b21b7edc86252fd7bb8f3b5182a06d 100644 (file)
@@ -147,6 +147,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_managed_oom_preference, managed_oom_prefer
 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");
@@ -6286,6 +6287,7 @@ void unit_dump_config_items(FILE *f) {
                 { 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" },
index 26b8de28f7a09d6a18c4e2f43daa817393978832..8842d7ddc8acdad3576d0085d256b26aa06d8d12 100644 (file)
@@ -78,6 +78,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
 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);
index 467e1dd57c789116860b7a99e9ef6fe6e62b8c23..9ad208fdfca83e2e7cd1158b5a84e03ce4f87df6 100644 (file)
@@ -691,6 +691,7 @@ static int parse_config_file(void) {
                         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
index 4b1c5d303d17f894199c97ee836a13bdc24b9850..54a6cc63e4b4a9d55c4fde55ed20264311a1ab3f 100644 (file)
@@ -490,7 +490,7 @@ static int scope_start(Unit *u) {
         (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);
 
@@ -627,6 +627,33 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
                 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);
 
@@ -755,6 +782,7 @@ static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
         [SCOPE_SUCCESS]           = "success",
         [SCOPE_FAILURE_RESOURCES] = "resources",
         [SCOPE_FAILURE_TIMEOUT]   = "timeout",
+        [SCOPE_FAILURE_OOM_KILL]  = "oom-kill",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
@@ -805,6 +833,7 @@ const UnitVTable scope_vtable = {
         .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,
index def1541652bc494cdd874a8cbe4dd007c01a85cc..6a228f1177d027d96370eb5a0faf03505275b9b2 100644 (file)
@@ -11,6 +11,7 @@ typedef enum ScopeResult {
         SCOPE_SUCCESS,
         SCOPE_FAILURE_RESOURCES,
         SCOPE_FAILURE_TIMEOUT,
+        SCOPE_FAILURE_OOM_KILL,
         _SCOPE_RESULT_MAX,
         _SCOPE_RESULT_INVALID = -EINVAL,
 } ScopeResult;
index 07c83c90a4c1e0aa9b8ae929f69407b962ea166a..0798c29c9d469f3a1f5038866a38154c64db74af 100644 (file)
@@ -5167,6 +5167,9 @@ void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) {
 
                                 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;
                         }
index 045adf871a1666d5ce76f1b4855bcd75ee81e80d..6f0c1ea95bf308c17c368036cde665350ada0413 100644 (file)
@@ -14,6 +14,7 @@
 #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"
@@ -28,6 +29,7 @@
 #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;
@@ -47,10 +49,12 @@ static int arg_fido2_cred_alg = 0;
 
 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 ||
@@ -92,6 +96,8 @@ static int help(void) {
                "     --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"
@@ -127,6 +133,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERSION = 0x100,
                 ARG_PASSWORD,
                 ARG_RECOVERY_KEY,
+                ARG_UNLOCK_KEYFILE,
                 ARG_PKCS11_TOKEN_URI,
                 ARG_FIDO2_DEVICE,
                 ARG_TPM2_DEVICE,
@@ -144,6 +151,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "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     },
@@ -221,6 +229,12 @@ static int parse_argv(int argc, char *argv[]) {
                         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;
 
@@ -473,6 +487,35 @@ static int prepare_luks(
         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");
@@ -536,6 +579,7 @@ static int prepare_luks(
                 }
         }
 
+out:
         *ret_cd = TAKE_PTR(cd);
         *ret_volume_key = TAKE_PTR(vk);
         *ret_volume_key_size = vks;
index 0716914b26f38bc9ddca8fa43748330f0a6fc1e5..9169129a6880776464d3e9dbcce3782c1102d4f5 100644 (file)
@@ -479,8 +479,9 @@ static int process_timezone(void) {
                                 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;
@@ -497,8 +498,9 @@ static int process_timezone(void) {
         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;
@@ -595,21 +597,8 @@ static int prompt_root_password(void) {
         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;
index 954e154f574ab9bf6c89be8fff9db74fd4544eb4..e7afbd3eb3aa23a1e8ad05280bf5f58e4ac04401 100644 (file)
@@ -1746,7 +1746,7 @@ static int server_parse_config_file(Server *s) {
                                 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;
 
index 5c5446e9876fa844d4ff05002fc487b1d5e95d30..215b6cf87fefb1100b5fa177eb0ef71cf8289680 100644 (file)
@@ -785,6 +785,8 @@ global:
         sd_bus_error_setfv;
 
         sd_device_new_child;
+        sd_device_monitor_set_description;
+        sd_device_monitor_get_description;
 
         sd_id128_string_equal;
 
index 01d45a941f98db97ff23185e6fba69a98ab8bf24..30f2520b7245eed5febba2f0d6bc809ae279553f 100644 (file)
@@ -742,8 +742,6 @@ static int enumerator_scan_dir(
         if (!dir)
                 return -errno;
 
-        log_debug("sd-device-enumerator: Scanning %s", path);
-
         FOREACH_DIRENT_ALL(de, dir, return -errno) {
                 int k;
 
@@ -949,8 +947,6 @@ static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
 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");
index 459dbdf4e49eb2263aae83956f5b7dbe82bad235..566280d66f3f03da729a64fa2dfaf7d2c6c4918b 100644 (file)
 #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;
 
@@ -46,6 +55,7 @@ struct sd_device_monitor {
 
         sd_event *event;
         sd_event_source *event_source;
+        char *description;
         sd_device_monitor_handler_t callback;
         void *userdata;
 };
@@ -139,14 +149,14 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
                  * 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);
@@ -164,7 +174,7 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
         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;
                 }
         }
@@ -179,12 +189,12 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
 
                 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;
                         }
 
@@ -192,12 +202,12 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
                                 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.");
                 }
         }
 
@@ -263,7 +273,7 @@ _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_han
         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;
 }
@@ -306,6 +316,29 @@ _public_ sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *
         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;
 
@@ -313,22 +346,22 @@ int device_monitor_enable_receiving(sd_device_monitor *m) {
 
         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;
@@ -339,6 +372,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
 
         (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);
@@ -446,49 +480,49 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
 
         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;
 
@@ -499,18 +533,18 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
                 /* 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);
@@ -518,9 +552,9 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
         /* 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);
 
@@ -576,15 +610,15 @@ int device_monitor_send_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)
@@ -616,13 +650,13 @@ int device_monitor_send_device(
         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;
 }
 
index 1050234afe980c21d8702696eac218615c498804..8574337bda9670a04fa7bcd7ea1ba47ce1a8c7b0 100644 (file)
@@ -145,15 +145,12 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
         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?) */
@@ -230,6 +227,12 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                                                        "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();
@@ -250,13 +253,16 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
         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;
@@ -269,6 +275,10 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
         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;
@@ -516,7 +526,7 @@ _public_ int sd_device_new_from_path(sd_device **ret, const char *path) {
         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) {
index 67f9bf4ae11283b795e04b2138522751c741d729..66ca63600d7b3ebd834118824af8312bfaba8dc9 100644 (file)
@@ -10,6 +10,7 @@
 #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"
@@ -39,13 +40,13 @@ static void test_receive_device_fail(void) {
         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);
@@ -61,13 +62,13 @@ static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool
         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);
@@ -98,14 +99,14 @@ static void test_subsystem_filter(sd_device *device) {
         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);
@@ -115,6 +116,9 @@ static void test_subsystem_filter(sd_device *device) {
                 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);
         }
@@ -135,14 +139,14 @@ static void test_tag_filter(sd_device *device) {
         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) {
@@ -150,6 +154,9 @@ static void test_tag_filter(sd_device *device) {
 
                 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);
         }
@@ -163,27 +170,23 @@ static void test_tag_filter(sd_device *device) {
 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);
@@ -192,8 +195,16 @@ static void test_sysattr_filter(sd_device *device, const char *sysattr) {
 
                 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);
@@ -205,39 +216,46 @@ static void test_sysattr_filter(sd_device *device, const char *sysattr) {
 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);
@@ -255,13 +273,13 @@ static void test_sd_device_monitor_filter_remove(sd_device *device) {
         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);
index d625dde85d89af4c50a53e7e3482b53809255ef3..8172c64e456d31d60dc40b583b2099048c54d9e4 100644 (file)
@@ -2,6 +2,7 @@
 
 #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;
@@ -406,4 +409,50 @@ TEST(sd_device_new_from_nulstr) {
         }
 }
 
+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);
index cb6a6fb51463f13c3dd4bdb988810ac8cebba28c..98736856ee850149abe6b0364ebb2947490a7eaa 100644 (file)
@@ -411,16 +411,18 @@ static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, con
 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);
index e9fadfddde8e8fa81e020c9a6dc0f23fe2434bf4..464f47f2cf78da81d4131ade6057a9c746c6ab3b 100644 (file)
@@ -789,6 +789,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
                         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. */
@@ -823,7 +824,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
                         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. */
 
index ce5262fcd6907c8337c98c1204004f4095bb024a..94771278855ed748a385afe1eb31f69825740e8b 100644 (file)
@@ -4,6 +4,7 @@
 #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"
@@ -187,12 +188,10 @@ int manager_request_product_uuid(Manager *m) {
 
         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,
index fe0a739410677909bd49f80e4eeec9b12f6a0017..9b77f536c8e9f3b4224571e615f3e8f8b78c9a78 100644 (file)
@@ -993,12 +993,10 @@ int manager_set_hostname(Manager *m, const char *hostname) {
                 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,
index 4faa43b3279eddec6f86f20b8caaf09f5eb006f0..61b900ada2dfcb13df33f8e891c5ee9dca57469e 100644 (file)
@@ -550,7 +550,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                         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. */
 
index 4c0d3d23c3dae4f6a4c294d2c48637848cf0c825..f9d774eee9e38331305b1f6e9efd253641c9cc88 100644 (file)
@@ -232,7 +232,7 @@ static int link_configure_fill_message(
                         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;
                 }
@@ -256,7 +256,7 @@ static int link_configure_fill_message(
                 }
 
                 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;
                 }
index 3d44c8fc82c9bd7787da6ef5c01897adb05b3667..5c270741bbd650d223dfbdbb7c4b6b00ee75c55e 100644 (file)
@@ -158,7 +158,7 @@ static int manager_update_sr_iov_ifindices(Manager *manager, int phys_port_ifind
         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)
index 6aef268d1f98dd7390ed92311b88a2c124fa5880..8f8a7408a587e0a7eb8ff7b26f1babc1f746f97c 100644 (file)
@@ -353,10 +353,17 @@ static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) {
         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) {
index adaaf260c471a3161a60a91d22b47d35b6523421..155e2adf24871380d532af02a3f057c7fb913f22 100644 (file)
@@ -56,6 +56,7 @@ typedef struct QDiscVTable {
         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];
index 1422860f55dcc5825de92c17b7ad0c96bf796aa0..9fd9e090069e752d3c64232f6f749fdd679a179a 100644 (file)
@@ -1,6 +1,7 @@
 /* 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"
@@ -17,9 +18,24 @@ static int trivial_link_equalizer_verify(QDisc *qdisc) {
         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(
index b41e3663098544f6525b8902ddd4689c7e48b47e..f4c196ee10db3472a99bfd314ef1b5c0ad2e368e 100644 (file)
@@ -38,6 +38,11 @@ static const sd_bus_vtable manager_vtable[] = {
                                  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
 };
 
index a28e97a178a4b7e45337dc036a87ba3ade98a5e1..d9574fa97b2fbfa68f29f9446903b228549433f9 100644 (file)
@@ -83,7 +83,7 @@ static int process_managed_oom_message(Manager *m, uid_t uid, JsonVariant *param
 
                         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;
                         }
 
@@ -410,7 +410,7 @@ static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void
                 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,
@@ -418,6 +418,16 @@ static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void
                                            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;
                 }
         }
@@ -524,13 +534,23 @@ static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t
                                  * 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;
                         }
                 }
index 84e6c47d6745148b394cc262379b077803ef2c72..b250be71c83342eacd1686e52dc4bb0595d89af7 100644 (file)
@@ -133,6 +133,7 @@ typedef enum EncryptMode {
 
 struct Partition {
         char *definition_path;
+        char **drop_in_files;
 
         sd_id128_t type_uuid;
         sd_id128_t current_uuid, new_uuid;
@@ -266,6 +267,7 @@ static Partition* partition_free(Partition *p) {
         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);
@@ -1310,7 +1312,7 @@ static int config_parse_gpt_flags(
         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        },
@@ -1336,13 +1338,25 @@ static int partition_read_definition(Partition *p, const char *path) {
                 {}
         };
         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;
 
@@ -1396,13 +1410,15 @@ static int context_read_definitions(
         _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 = directory ?
+                STRV_MAKE_CONST(directory) :
+                (const char* const*)CONF_PATHS_STRV("repart.d");
+
+        r = conf_files_list_strv(&files, ".conf", directory ? NULL : root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, dirs);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate *.conf files: %m");
 
@@ -1417,7 +1433,7 @@ static int context_read_definitions(
                 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;
 
@@ -1988,23 +2004,26 @@ static int context_dump_partitions(Context *context, const char *node) {
         _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);
@@ -2058,9 +2077,12 @@ static int context_dump_partitions(Context *context, const char *node) {
                                 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)) {
@@ -2083,11 +2105,18 @@ static int context_dump_partitions(Context *context, const char *node) {
                                 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);
 }
 
index 2b9bebbe8ccc5fbe1986986399c027860ae4f06a..13df482e00d96799c6987e5cb31ec1be71fd6fc8 100755 (executable)
@@ -222,3 +222,53 @@ echo "### Testing json output ###"
 "$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
index aaa1c497c02c8d6d4d71799778f68717ab4123b1..6d08821ecd63a9eff9cccc673995a0b9ccd05608 100644 (file)
@@ -138,7 +138,7 @@ int ifname_resolvconf_mangle(const char *s) {
 
         assert(s);
 
-        dot = strchr(s, '.');
+        dot = strrchr(s, '.');
         if (dot) {
                 _cleanup_free_ char *iface = NULL;
 
index 84193eacc1d7ea2c5db0cd81c126392d44303895..464892a8fe03ce411ef056cd256e994d3e67a983 100644 (file)
@@ -93,6 +93,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
                         config_item_perf_lookup, resolved_dnssd_gperf_lookup,
                         CONFIG_PARSE_WARN,
                         service,
+                        NULL,
                         NULL);
         if (r < 0)
                 return r;
index 3754d1dd68c88bac49f31f5a1890ce1d85b12bf9..5b9a6dbc438f681e5e817b361a8487206939ed88 100644 (file)
@@ -63,6 +63,12 @@ const BusLocator* const bus_timedate = &(BusLocator){
         .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(
index fe3b8765279312d25d234f06f30049ed5a4d675d..9662c906e18d72fba31952cd138ff30d4b3fdb6a 100644 (file)
@@ -19,6 +19,7 @@ extern const BusLocator* const bus_portable_mgr;
 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. */
index 737bbd3d36c1402e377885250fad4b39549f5426..27b6f88cd0557388b51f739c6899f2b45b7f97c0 100644 (file)
@@ -151,7 +151,10 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
 
                         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) ||
index 1c96519b55ed2a34a7242213ab1fbe54a3cfb2c8..edc2cfa9373253905859d0a9c41aa48d1c06412f 100644 (file)
@@ -130,6 +130,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
 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);
@@ -466,8 +467,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                 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);
 
index a1fabc73c111e2bf6c88485b1d7b37fb225376c3..c3bf7348ffe9caa531a5e69180dffc48e28a48d1 100644 (file)
@@ -173,6 +173,12 @@ int cg_weight_parse(const char *s, uint64_t *ret) {
         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;
index 7eabce24512dedf101c27545d4a39b4946579133..95a515339d66d339711cd9528e4c5f7c23225b17 100644 (file)
@@ -12,6 +12,7 @@ bool cg_is_legacy_wanted(void);
 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);
 
index 765ccec5016d765a2cb9c928e58ffcfc8af0a703..887ae0dd61644621818d431a4e76a0814f51954a 100644 (file)
@@ -588,7 +588,8 @@ int config_parse_many(
                 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;
@@ -602,7 +603,14 @@ int config_parse_many(
         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(
index bd57575af127c613efeb763a8b39870a73e8f633..32f2498b53e350576448db0fcbdcf3fe563cbef1 100644 (file)
@@ -112,7 +112,8 @@ int config_parse_many(
                 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,
index 72ec992121f67b86c5f8fcfb99b6c6390fa86963..c1a9d35528dc4682ec709918e4ce354194d034e6 100644 (file)
@@ -83,6 +83,38 @@ int read_credential(const char *name, void **ret, size_t *ret_size) {
                         (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
index ccbecaf58bd4a6495f59eb58d361f4c1edf64c8a..62e5c888eecf76f912987346a868e265cc74aa84 100644 (file)
@@ -44,6 +44,8 @@ typedef enum CredentialSecretFlags {
 
 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
index e95072e048904ab9e56fd18510acbb891972a37a..18748e537627376c612e303cb8b24cd47bb8979c 100644 (file)
@@ -24,6 +24,7 @@ static const NamingScheme naming_schemes[] = {
         { "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
index 5303348e063e832474b723b4801843b24452323f..4fa917096907c305e1aa77f17dc6af4ddc747d47 100644 (file)
@@ -37,6 +37,7 @@ typedef enum NamingSchemeFlags {
         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,
@@ -49,6 +50,7 @@ typedef enum NamingSchemeFlags {
         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
 
index b18f6bf3f48d46864f2cf20a39b28905331234a0..d9923e9de8fb367d01fe68cc8814b9338c4cc93d 100644 (file)
 #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,
@@ -108,77 +125,177 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) {
         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)
@@ -196,7 +313,7 @@ static int get_system_battery_identifier_hash(uint64_t *ret_hash) {
         else
                siphash24_compress(&product_id, sizeof(sd_id128_t), &state);
 
-        *ret_hash = siphash24_finalize(&state);
+        *ret = siphash24_finalize(&state);
 
         return 0;
 }
@@ -208,66 +325,204 @@ static bool battery_discharge_rate_is_valid(int battery_discharge_rate) {
 
 /* 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, &current_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(&current_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;
 }
 
index a48cf17a54ec63b56111e03338201a8741de6a6f..54fe65007ede17aa0eaf3baf659411f1e34d7e92 100644 (file)
@@ -2,6 +2,8 @@
 #pragma once
 
 #include <linux/fiemap.h>
+
+#include "hashmap.h"
 #include "time-util.h"
 
 typedef enum SleepOperation {
@@ -55,10 +57,14 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location);
 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_;
index abcedde8a89d53ab7250e9f585af1d33340f3d2a..0eb6da3de000007511d9666ebd353c314c281dcb 100644 (file)
@@ -280,17 +280,15 @@ static int tpm2_make_primary(
                         .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,
                         },
                 },
         };
@@ -300,16 +298,14 @@ static int tpm2_make_primary(
                         .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,
                         },
                 },
         };
@@ -602,7 +598,7 @@ static int tpm2_get_best_pcr_bank(
 
 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 = {
@@ -628,7 +624,7 @@ static int tpm2_make_encryption_session(
          * 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,
@@ -663,7 +659,7 @@ static int tpm2_make_encryption_session(
 
 static int tpm2_make_pcr_session(
                 ESYS_CONTEXT *c,
-                ESYS_TR tpmKey,
+                ESYS_TR primary,
                 ESYS_TR parent_session,
                 uint32_t pcr_mask,
                 uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
@@ -674,12 +670,8 @@ static int tpm2_make_pcr_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,
         };
         _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
         TPML_PCR_SELECTION pcr_selection;
@@ -713,7 +705,7 @@ static int tpm2_make_pcr_session(
 
         rc = sym_Esys_StartAuthSession(
                         c,
-                        tpmKey,
+                        primary,
                         ESYS_TR_NONE,
                         parent_session,
                         ESYS_TR_NONE,
@@ -902,16 +894,8 @@ int tpm2_seal(
                         .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,
                 },
         };
index 95895a8e458dc2b645dab62c761fcda2f172e3e1..4e46a2fe3fbad1be0bd42616612ec49bf6b94097 100644 (file)
@@ -276,7 +276,9 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
         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)
index ff6c71d61b6a3a59b3be3c6117366dcb0bc6f648..14191cfc61c593c0356d4873235a3b4d9321634a 100644 (file)
@@ -263,6 +263,7 @@ static int execute(
 }
 
 static int execute_s2h(const SleepConfig *sleep_config) {
+        _cleanup_hashmap_free_ Hashmap *last_capacity = NULL, *current_capacity = NULL;
         int r;
 
         assert(sleep_config);
@@ -270,42 +271,29 @@ static int execute_s2h(const SleepConfig *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);
@@ -323,28 +311,26 @@ static int execute_s2h(const SleepConfig *sleep_config) {
                 /* 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(&current_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 */
index 0b2f8f8b4292d8ccbfc8ae4e0dced6549871e563..41d3f832913c0118a57c0144ce6ecb5a1d1177e5 100644 (file)
@@ -144,6 +144,8 @@ int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event);
 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);
 
index 901e8aaf02e001dba6c816eed73a961e72cfcd41..dfb703f10ec3bd5fa5b5c3fd2b375f964f684a7c 100644 (file)
@@ -581,7 +581,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
 
         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,
@@ -595,30 +595,16 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
                         .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;
index 85cf5201c6a1d9960debfb60ddcfef89e9bd6460..d2c126212182993f56aa714f2c3be3c7dc0d709d 100644 (file)
@@ -704,7 +704,7 @@ static int cd_media_toc(Context *c) {
         /* 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;
 
index 693f5cd3a60279a5699928b3a3807307d67ea431..3863808fb030b51d3a432a9aaf24400356b6415d 100644 (file)
@@ -264,7 +264,8 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
                         "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. */
 
index 45387b2bdbedee88e8901a3cca0cd491fb9b5bef..33fce6e140613fabd172c166b81adb3535acce3d 100644 (file)
@@ -23,6 +23,7 @@
 #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"
@@ -52,6 +53,7 @@ typedef enum NetNameType {
         NET_XENVIF,
         NET_PLATFORM,
         NET_NETDEVSIM,
+        NET_DEVICETREE,
 } NetNameType;
 
 typedef struct NetNames {
@@ -70,6 +72,7 @@ typedef struct NetNames {
         char xen_slot[ALTIFNAMSIZ];
         char platform_path[ALTIFNAMSIZ];
         char netdevsim_path[ALTIFNAMSIZ];
+        char devicetree_onboard[ALTIFNAMSIZ];
 } NetNames;
 
 /* skip intermediate virtio devices */
@@ -600,6 +603,94 @@ static int names_platform(sd_device *dev, NetNames *names, bool test) {
         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;
@@ -1036,6 +1127,15 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
                 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];
index 0a68b7e6ac18356f7eda1c34eace8177aa449176..70a5394b16ae63bbfef776e63de851a28e03dfe8 100644 (file)
@@ -797,6 +797,8 @@ static int worker_spawn(Manager *manager, Event *event) {
         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)
@@ -1919,6 +1921,8 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent) {
                         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");
index 4b5ba622fa6f31e6c33e15299d271dd651c0b772..0a5ba11f89e08e6a4439306a518236d370102288 100755 (executable)
@@ -291,8 +291,8 @@ Priority=23
         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."""
diff --git a/test/test-network/conf/25-qdisc-clsact-and-htb.network b/test/test-network/conf/25-qdisc-clsact-and-htb.network
deleted file mode 100644 (file)
index c91666d..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-# 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
diff --git a/test/test-network/conf/25-qdisc-clsact.network b/test/test-network/conf/25-qdisc-clsact.network
new file mode 100644 (file)
index 0000000..8a16618
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[QDisc]
+Parent=clsact
diff --git a/test/test-network/conf/25-qdisc-codel.network b/test/test-network/conf/25-qdisc-codel.network
new file mode 100644 (file)
index 0000000..a332fa8
--- /dev/null
@@ -0,0 +1,16 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-fq.network b/test/test-network/conf/25-qdisc-fq.network
new file mode 100644 (file)
index 0000000..5539a64
--- /dev/null
@@ -0,0 +1,20 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-fq_codel.network b/test/test-network/conf/25-qdisc-fq_codel.network
new file mode 100644 (file)
index 0000000..0e7d62d
--- /dev/null
@@ -0,0 +1,19 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-gred.network b/test/test-network/conf/25-qdisc-gred.network
new file mode 100644 (file)
index 0000000..a49955f
--- /dev/null
@@ -0,0 +1,14 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-htb-fifo.network b/test/test-network/conf/25-qdisc-htb-fifo.network
new file mode 100644 (file)
index 0000000..1e092a9
--- /dev/null
@@ -0,0 +1,65 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-ingress.network b/test/test-network/conf/25-qdisc-ingress.network
new file mode 100644 (file)
index 0000000..6fb5fef
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=test1
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.4/16
+
+[QDisc]
+Parent=ingress
similarity index 84%
rename from test/test-network/conf/25-qdisc-ingress-netem-compat.network
rename to test/test-network/conf/25-qdisc-netem-compat.network
index d895f7f34fe5756b17e70fc807a2b56f760dd959..15e0f7f36767d64e7cf1fe28b29ef4a95efb48e5 100644 (file)
@@ -12,6 +12,3 @@ NetworkEmulatorDelaySec=50ms
 NetworkEmulatorDelayJitterSec=10ms
 NetworkEmulatorLossRate=20%
 NetworkEmulatorPacketLimit=100
-
-[TrafficControlQueueingDiscipline]
-Parent=ingress
diff --git a/test/test-network/conf/25-qdisc-netem.network b/test/test-network/conf/25-qdisc-netem.network
new file mode 100644 (file)
index 0000000..9848788
--- /dev/null
@@ -0,0 +1,15 @@
+# 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
index 1c8dbc2461dfb916a084cbdb6b473391c452e334..b09e99c4f2634c2a4a139b24106b9989db487b8c 100644 (file)
@@ -1,10 +1,10 @@
 # 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
diff --git a/test/test-network/conf/25-qdisc-sfb.network b/test/test-network/conf/25-qdisc-sfb.network
new file mode 100644 (file)
index 0000000..bfcda00
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-sfq.network b/test/test-network/conf/25-qdisc-sfq.network
new file mode 100644 (file)
index 0000000..263cd6d
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-tbf.network b/test/test-network/conf/25-qdisc-tbf.network
new file mode 100644 (file)
index 0000000..c5f28fb
--- /dev/null
@@ -0,0 +1,16 @@
+# 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
diff --git a/test/test-network/conf/25-qdisc-teql.network b/test/test-network/conf/25-qdisc-teql.network
new file mode 100644 (file)
index 0000000..ed7e21f
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
index 5c1f97be9ea306356966c3fe24657db47f26227b..f52d2555608240a0f27262d1faaabeccb68ae6ec 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [NetDev]
-Name=tap99
+Name=testtap99
 Kind=tap
 
 [Tap]
index ed25026a95925898311312939ccfe0700b58ebc4..8ab2f5a03854583bad93809655c9206e37a5c091 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [NetDev]
-Name=tun99
+Name=testtun99
 Kind=tun
 
 [Tun]
index 9266441944cb30537005b1073ae9dcd737e9aaa4..f3ec22aeee460dd75a24c2986f0bfe67e8f84211 100755 (executable)
@@ -38,13 +38,16 @@ which_paths = ':'.join(systemd_lib_paths + os.getenv('PATH', os.defpath).lstrip(
 
 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 = {}
@@ -92,24 +95,29 @@ def mkdir_p(path):
 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')
@@ -231,53 +239,8 @@ def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
 
     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):
     """
@@ -371,7 +334,7 @@ def clear_udev_rules():
 
 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}')
@@ -383,6 +346,49 @@ def restore_active_units():
     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'))
 
@@ -497,14 +503,14 @@ def flush_l2tp_tunnels():
 
 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:
@@ -595,8 +601,11 @@ def start_networkd():
     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 networkctl_reconfigure(*links):
     check_output(*networkctl_cmd, 'reconfigure', *links, env=env)
@@ -657,93 +666,40 @@ def setUpModule():
     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',
-        ]
-
-    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',
+    )
+    create_unit_dropin(
+        'systemd-networkd.socket',
+        [
+            '[Unit]',
+            'StartLimitIntervalSec=0',
         ]
-
-    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():
@@ -755,7 +711,9 @@ 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')
@@ -886,7 +844,7 @@ class Utilities():
         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):
@@ -1362,24 +1320,18 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         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')
         start_networkd()
 
-        self.wait_online(['tun99:off'], setup_state='unmanaged')
+        self.wait_online(['testtun99:off', 'testtap99:off'], setup_state='unmanaged')
 
-        output = check_output('ip -d link show tun99')
+        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) ')
 
-    def test_tap(self):
-        copy_network_unit('25-tap.netdev')
-        start_networkd()
-
-        self.wait_online(['tap99:off'], setup_state='unmanaged')
-
-        output = check_output('ip -d link show tap99')
+        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) ')
@@ -3281,59 +3233,146 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         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')
+
+    @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'])
 
-        self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+
+        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')
 
-        self.assertRegex(output, 'qdisc fq 32: parent 2:32')
+    @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')
@@ -3345,16 +3384,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
 
         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:')
@@ -3362,50 +3392,39 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         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()
@@ -3416,42 +3435,74 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         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()
 
     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')
@@ -3735,8 +3786,8 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         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',
@@ -3772,8 +3823,8 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         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)
@@ -3952,7 +4003,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             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)
@@ -3968,7 +4019,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             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)
@@ -3984,7 +4035,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             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)
@@ -4000,7 +4051,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             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)
@@ -5307,11 +5358,13 @@ if __name__ == '__main__':
     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')
@@ -5321,20 +5374,25 @@ if __name__ == '__main__':
     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:
@@ -5345,6 +5403,8 @@ if __name__ == '__main__':
             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
@@ -5354,15 +5414,14 @@ if __name__ == '__main__':
     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})
@@ -5370,6 +5429,8 @@ if __name__ == '__main__':
         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:
index 66357ab688bf5c36062ba078ba1558bc78f5d695..2f4d93ab8cd11b7cb896cda8abaaab440728c48f 100644 (file)
@@ -4,10 +4,10 @@
 # utility functions for shell tests
 
 assert_true() {(
-    local rc
-
     set +ex
 
+    local rc
+
     "$@"
     rc=$?
     if [[ $rc -ne 0 ]]; then
@@ -47,10 +47,10 @@ assert_not_in() {(
 )}
 
 assert_rc() {(
-    local rc exp="${1?}"
-
     set +ex
 
+    local rc exp="${1?}"
+
     shift
     "$@"
     rc=$?
diff --git a/test/units/testsuite-17.07.sh b/test/units/testsuite-17.07.sh
new file mode 100755 (executable)
index 0000000..549107a
--- /dev/null
@@ -0,0 +1,205 @@
+#!/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
index 6ebb1c72c959df391e9a7a5da50773b04f36b8cf..fdd24e2862556abf9e09264284060eea6511813e 100755 (executable)
@@ -11,6 +11,9 @@ dd if=/dev/zero of=$img bs=1024k count=20 status=none
 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
index f140b7817406b798b371f1b19774466dbeecf3e5..361376fd21e3ecb6a61b4bbe0f4b79c873b39976 100755 (executable)
 #!/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
diff --git a/tools/get-coverity.sh b/tools/get-coverity.sh
deleted file mode 100755 (executable)
index b067ed2..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/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"