]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #10088 from keszybz/man-systemctl-return
authorLennart Poettering <lennart@poettering.net>
Tue, 25 Sep 2018 10:35:36 +0000 (12:35 +0200)
committerGitHub <noreply@github.com>
Tue, 25 Sep 2018 10:35:36 +0000 (12:35 +0200)
man: add a description of systemctl return codes

228 files changed:
NEWS
README.md
TODO
docs/CGROUP_DELEGATION.md
docs/HACKING
hwdb/60-sensor.hwdb
hwdb/70-mouse.hwdb
hwdb/meson.build
man/systemd-inhibit.xml
man/systemd.exec.xml
man/systemd.network.xml
meson.build
src/analyze/analyze.c
src/backlight/backlight.c
src/basic/btrfs-util.c
src/basic/calendarspec.c
src/basic/conf-files.c
src/basic/exec-util.c
src/basic/exec-util.h
src/basic/format-table.c
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/mount-util.c
src/basic/mount-util.h
src/basic/process-util.c
src/basic/process-util.h
src/basic/strbuf.c
src/basic/strv.c
src/basic/strv.h
src/basic/util.c
src/basic/util.h
src/basic/verbs.c
src/basic/virt.c
src/boot/efi/meson.build
src/busctl/busctl.c
src/cgtop/cgtop.c
src/core/bpf-firewall.c
src/core/device.c
src/core/execute.c
src/core/job.c
src/core/manager.c
src/core/namespace.c
src/core/shutdown.c
src/core/socket.c
src/core/umount.c
src/cryptsetup/cryptsetup.c
src/fsck/fsck.c
src/fuzz/fuzz-main.c
src/gpt-auto-generator/gpt-auto-generator.c
src/hwdb/hwdb.c
src/import/import-compress.c
src/import/import-compress.h
src/journal/catalog.c
src/journal/journal-file.c
src/journal/journal-vacuum.c
src/journal/test-catalog.c
src/journal/test-compress-benchmark.c
src/journal/test-compress.c
src/journal/test-journal-enum.c
src/journal/test-journal-init.c
src/journal/test-journal-interleaving.c
src/journal/test-journal-match.c
src/journal/test-journal-stream.c
src/journal/test-journal-verify.c
src/journal/test-journal.c
src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-lease-internal.h
src/libsystemd-network/lldp-neighbor.c
src/libsystemd-network/lldp-neighbor.h
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-dhcp6-lease.c
src/libsystemd-network/sd-lldp.c
src/libsystemd-network/test-acd.c
src/libsystemd-network/test-dhcp-client.c
src/libsystemd-network/test-dhcp-server.c
src/libsystemd-network/test-dhcp6-client.c
src/libsystemd-network/test-ipv4ll-manual.c
src/libsystemd-network/test-ipv4ll.c
src/libsystemd-network/test-ndisc-ra.c
src/libsystemd-network/test-ndisc-rs.c
src/libsystemd/meson.build
src/libsystemd/sd-bus/bus-match.c
src/libsystemd/sd-bus/test-bus-chat.c
src/libsystemd/sd-bus/test-bus-cleanup.c
src/libsystemd/sd-bus/test-bus-creds.c
src/libsystemd/sd-bus/test-bus-gvariant.c
src/libsystemd/sd-bus/test-bus-marshal.c
src/libsystemd/sd-bus/test-bus-match.c
src/libsystemd/sd-bus/test-bus-track.c
src/libsystemd/sd-device/device-enumerator-private.h
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-private.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-event/test-event.c
src/libsystemd/sd-hwdb/hwdb-internal.h
src/libsystemd/sd-hwdb/hwdb-util.c [new file with mode: 0644]
src/libsystemd/sd-hwdb/hwdb-util.h
src/libsystemd/sd-hwdb/sd-hwdb.c
src/libsystemd/sd-netlink/local-addresses.c
src/libsystemd/sd-netlink/test-local-addresses.c
src/libudev/libudev-device-internal.h
src/libudev/libudev-device-private.c
src/libudev/libudev-device.c
src/libudev/libudev-enumerate.c
src/libudev/libudev-hwdb.c
src/libudev/libudev-monitor.c
src/libudev/libudev-private.h
src/libudev/libudev-queue.c
src/libudev/libudev.c
src/libudev/libudev.h
src/login/inhibit.c
src/login/logind-acl.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-session-device.c
src/login/logind.c
src/login/sysfs-show.c
src/machine/machinectl.c
src/mount/mount-tool.c
src/network/networkctl.c
src/network/networkd-dhcp6.c
src/network/networkd-link.h
src/network/networkd-manager.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.h
src/network/test-network.c
src/network/test-routing-policy-rule.c
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-mount.c
src/nspawn/nspawn.c
src/nspawn/test-patch-uid.c
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-rr.h
src/resolve/resolved-dns-trust-anchor.c
src/resolve/resolved-mdns.c
src/rfkill/rfkill.c
src/shared/bootspec.c
src/shared/bus-unit-util.c
src/shared/bus-util.h
src/shared/cgroup-show.c
src/shared/dissect-image.c
src/shared/efivars.c
src/shared/machine-pool.c
src/shared/tests.c
src/shared/tests.h
src/shared/uid-range.c
src/sleep/sleep.c
src/systemctl/systemctl.c
src/systemd/meson.build
src/systemd/sd-device.h
src/systemd/sd-dhcp6-client.h
src/test/meson.build
src/test/test-architecture.c
src/test/test-barrier.c
src/test/test-boot-timestamps.c
src/test/test-bpf.c
src/test/test-bus-util.c
src/test/test-capability.c
src/test/test-cgroup-mask.c
src/test/test-cgroup-util.c
src/test/test-condition.c
src/test/test-conf-files.c
src/test/test-copy.c
src/test/test-date.c
src/test/test-dissect-image.c
src/test/test-dns-domain.c
src/test/test-engine.c
src/test/test-escape.c
src/test/test-exec-util.c
src/test/test-execute.c
src/test/test-fd-util.c
src/test/test-fileio.c
src/test/test-firewall-util.c
src/test/test-hash.c
src/test/test-hashmap-plain.c
src/test/test-install-root.c
src/test/test-install.c
src/test/test-ipcrm.c
src/test/test-journal-importer.c
src/test/test-loopback.c
src/test/test-mount-util.c
src/test/test-namespace.c
src/test/test-netlink-manual.c
src/test/test-ns.c
src/test/test-os-util.c
src/test/test-path-lookup.c
src/test/test-path-util.c
src/test/test-path.c
src/test/test-prioq.c
src/test/test-process-util.c
src/test/test-random-util.c
src/test/test-sched-prio.c
src/test/test-seccomp.c
src/test/test-selinux.c
src/test/test-sigbus.c
src/test/test-sleep.c
src/test/test-socket-util.c
src/test/test-specifier.c
src/test/test-strv.c
src/test/test-tmpfiles.c
src/test/test-umount.c
src/test/test-unit-file.c
src/test/test-unit-name.c
src/test/test-watch-pid.c
src/test/test-watchdog.c
src/test/test-xattr-util.c
src/timesync/test-timesync.c
src/tmpfiles/tmpfiles.c
src/udev/udev-builtin-net_id.c
src/udev/udevadm-control.c
src/udev/udevadm-hwdb.c
src/udev/udevadm-info.c
src/udev/udevadm-monitor.c
src/udev/udevadm-settle.c
src/udev/udevadm-test-builtin.c
src/udev/udevadm-test.c
src/udev/udevadm-trigger.c
src/udev/udevadm.c
src/udev/udevadm.h
test/meson.build
test/test-execute/exec-dynamicuser-statedir-migrate-step1.service
test/test-execute/exec-dynamicuser-statedir-migrate-step2.service
test/test-execute/exec-dynamicuser-statedir.service
test/test-execute/exec-runtimedirectory-mode.service
test/test-execute/exec-runtimedirectory.service
test/test-functions
units/meson-add-wants.sh
units/systemd-tmpfiles-setup.service.in

diff --git a/NEWS b/NEWS
index 3bebe5a036b7a30388860adb8d363d3f3efee26d..a8a30aaa07fa927ee1de7bfeceb6909cd9c3e30e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -594,10 +594,9 @@ CHANGES WITH 237:
           different from what the documentation said, and not particularly
           useful, as repeated systemd-tmpfiles invocations would not be
           idempotent and grow such files without bounds. With this release
-          behaviour has been altered slightly, to match what the documentation
-          says: lines of this type only have an effect if the indicated files
-          don't exist yet, and only then the argument string is written to the
-          file.
+          behaviour has been altered to match what the documentation says:
+          lines of this type only have an effect if the indicated files don't
+          exist yet, and only then the argument string is written to the file.
 
         * FUTURE INCOMPATIBILITY: In systemd v238 we intend to slightly change
           systemd-tmpfiles behaviour: previously, read-only files owned by root
index bebe259a8106995447181c939fbf17ac3b0084f2..b0b0a86538494f02ec46c8e534ae1f21dceb02fd 100644 (file)
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Consult our [NEWS file](../master/NEWS) for information about what's new in the
 
 Please see the [HACKING file](../master/docs/HACKING) for information how to hack on systemd and test your modifications.
 
-Please see our [Contribution Guidelines](../master/.github/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
+Please see our [Contribution Guidelines](../master/docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
 
 When preparing patches for systemd, please follow our [Coding Style Guidelines](../master/docs/CODING_STYLE).
 
diff --git a/TODO b/TODO
index 24cb6829eacc4b4b7aa7624eb42e60cf9406a4a6..f3d6f56a4f1818618b4038697c47babe0ce26fc0 100644 (file)
--- a/TODO
+++ b/TODO
@@ -17,6 +17,8 @@ Janitorial Clean-ups:
 
 Features:
 
+* chown() tty a service is attached to after the service goes down
+
 * optionally, if a per-partition GPT flag is set for the root/home/… partitions
   format the partition on next boot and unset the flag, in order to implement
   factory reset. also, add a second flag that simply indicates whether such a
@@ -110,7 +112,7 @@ Features:
   zero and is not open anymore, while the latter happens when a file is
   unlinked from any dir.
 
-* port systemctl, systemd-inhibit, busctl, â€¦ over to format-table.[ch]'s table formatters
+* port systemctl, busctl, â€¦ over to format-table.[ch]'s table formatters
 
 * pid1: lock image configured with RootDirectory=/RootImage= using the usual nspawn semantics while the unit is up
 
@@ -247,15 +249,6 @@ Features:
   for all units. It should be both a way to pin units into memory as well as a
   wait to retrieve their exit data.
 
-* maybe set a new set of env vars for services, based on RuntimeDirectory=,
-  StateDirectory=, LogsDirectory=, CacheDirectory= and ConfigurationDirectory=
-  automatically. For example, there could be $RUNTIME_DIRECTORY,
-  $STATE_DIRECTORY, $LOGS_DIRECTORY=, $CACHE_DIRECTORY and
-  $CONFIGURATION_DIRECTORY or so. This could be useful to write services that
-  can adapt to varying directories for these purposes. Special care has to be
-  taken if multiple dirs are configured. Maybe avoid setting the env vars in
-  that case?
-
 * expose IO accounting data on the bus, show it in systemd-run --wait and log
   about it in the resource log message
 
@@ -447,8 +440,6 @@ Features:
 
 * hostnamectl: show root image uuid
 
-* sysfs set api in libudev is not const
-
 * Find a solution for SMACK capabilities stuff:
   http://lists.freedesktop.org/archives/systemd-devel/2014-December/026188.html
 
index 63d9d41b1093e4bda265c99f482ed2590b29ef18..c63b75e58b39e5604cf1c9bedf67d74568e25571 100644 (file)
@@ -91,10 +91,14 @@ hierarchy for managing purposes as `/sys/fs/cgroup/systemd/`.
 
 3. **Hybrid** â€” this is a hybrid between the unified and legacy mode. It's set
 up mostly like legacy, except that there's also an additional hierarchy
-`/sys/fs/cgroup/unified/` that contains the cgroupsv2 hierarchy. In this mode
-compatibility with cgroupsv1 is retained while some cgroupsv2 features are
-available too. This mode is a stopgap. Don't bother with this too much unless
-you have too much free time.
+`/sys/fs/cgroup/unified/` that contains the cgroupsv2 hierarchy. (Note that in
+this mode the unified hierarchy won't have controllers attached, the
+controllers are all mounted as separate hierarchies as in legacy mode,
+i.e. `/sys/fs/cgroup/unified/` is purely and exclusively about core cgroupsv2
+functionality and not about resource management.) In this mode compatibility
+with cgroupsv1 is retained while some cgroupsv2 features are available
+too. This mode is a stopgap. Don't bother with this too much unless you have
+too much free time.
 
 To say this clearly, legacy and hybrid modes have no future. If you develop
 software today and don't focus on the unified mode, then you are writing
index 1778e4822d207b406c525ab3c5b858e50da144eb..c975ca183e3d3fae9f100d4c934c247faaf38188 100644 (file)
@@ -109,7 +109,7 @@ commands like this:
         python infra/helper.py run_fuzzer systemd fuzz-foo
 
 If you find a bug that impacts the security of systemd, please follow the
-guidance in .github/CONTRIBUTING.md on how to report a security vulnerability.
+guidance in CONTRIBUTING.md on how to report a security vulnerability.
 
 For more details on building fuzzers and integrating with OSS-Fuzz, visit:
 
index 19fe970d0beb6708b97c3844410309d0f5cf0d13..9f26c45438129849a7a1c533f65867cf67526909 100644 (file)
@@ -389,6 +389,10 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnTECLAST:pnX80Pro:*
 sensor:modalias:acpi:KIOX000A*:dmi:*:svnTECLAST:pnX98PlusII:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
+# Teclast X98 Plus I (A5C6), generic DMI strings, match entire dmi modalias inc. bios-date
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
+ ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+
 #########################################
 # Trekstor
 #########################################
index 5f28d89d20eb8ca113e1c8106f5509b3e133170a..f5bde3c22424681b2bf1257042942aeb272a2a8a 100644 (file)
@@ -280,6 +280,14 @@ mouse:usb:v03f0p0641:name:PixArt HP X1200 USB Optical Mouse:
 mouse:usb:v04b3p3107:name:*
  MOUSE_DPI=800@125
 
+##########################################
+# Kensington
+##########################################
+
+# Kensington Expert Mouse trackball
+mouse:usb:v047dp1020:*Kensington Expert Mouse*
+ ID_INPUT_TRACKBALL=1
+
 ##########################################
 # Lenovo
 ##########################################
index 158292c712f4525b4908f526bce866f84862bcb2..31ee3e74094fb8bd2d5aee0033fc0a80a347b169 100644 (file)
@@ -36,9 +36,11 @@ endif
 ############################################################
 
 parse_hwdb_py = find_program('parse_hwdb.py')
-test('parse-hwdb',
-     parse_hwdb_py,
-     timeout : 90)
+if want_tests != 'false'
+        test('parse-hwdb',
+             parse_hwdb_py,
+             timeout : 90)
+endif
 
 ############################################################
 
index 03dc06678a290f20c1d03654a92ab5d3919dfb48..3fa5acf5503278d881c91977fe6b448eec961efd 100644 (file)
       </varlistentry>
 
       <xi:include href="standard-options.xml" xpointer="no-pager" />
+      <xi:include href="standard-options.xml" xpointer="no-legend" />
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
index 4cee4a508af91d77dcd4b5247048ead07d6b748c..bc1c36fdfb2d984d64e83735eb67411ccca1e7a4 100644 (file)
@@ -814,15 +814,18 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <listitem><para>These options take a whitespace-separated list of directory names. The specified directory
         names must be relative, and may not include <literal>..</literal>. If set, one or more
         directories by the specified names will be created (including their parents) below the locations
-        defined in the following table, when the unit is started.</para>
+        defined in the following table, when the unit is started. Also, the corresponding environment variable
+        is defined with the full path of directories. If multiple directories are set, then int the environment variable
+        the paths are concatenated with colon (<literal>:</literal>).</para>
         <table>
-          <title>Automatic directory creation</title>
-          <tgroup cols='3'>
+          <title>Automatic directory creation and environment variables</title>
+          <tgroup cols='4'>
             <thead>
               <row>
                 <entry>Locations</entry>
                 <entry>for system</entry>
                 <entry>for users</entry>
+                <entry>Environment variable</entry>
               </row>
             </thead>
             <tbody>
@@ -830,26 +833,31 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
                 <entry><varname>RuntimeDirectory=</varname></entry>
                 <entry><filename>/run</filename></entry>
                 <entry><varname>$XDG_RUNTIME_DIR</varname></entry>
+                <entry><varname>$RUNTIME_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>StateDirectory=</varname></entry>
                 <entry><filename>/var/lib</filename></entry>
                 <entry><varname>$XDG_CONFIG_HOME</varname></entry>
+                <entry><varname>$STATE_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>CacheDirectory=</varname></entry>
                 <entry><filename>/var/cache</filename></entry>
                 <entry><varname>$XDG_CACHE_HOME</varname></entry>
+                <entry><varname>$CACHE_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>LogsDirectory=</varname></entry>
                 <entry><filename>/var/log</filename></entry>
                 <entry><varname>$XDG_CONFIG_HOME</varname><filename>/log</filename></entry>
+                <entry><varname>$LOGS_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>ConfigurationDirectory=</varname></entry>
                 <entry><filename>/etc</filename></entry>
                 <entry><varname>$XDG_CONFIG_HOME</varname></entry>
+                <entry><varname>$CONFIGURATION_DIRECTORY</varname></entry>
               </row>
             </tbody>
           </tgroup>
@@ -899,7 +907,13 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         <filename>/run/foo/bar</filename>, and <filename>/run/baz</filename>. The directories
         <filename>/run/foo/bar</filename> and <filename>/run/baz</filename> except <filename>/run/foo</filename> are
         owned by the user and group specified in <varname>User=</varname> and <varname>Group=</varname>, and removed
-        when the service is stopped.</para></listitem>
+        when the service is stopped.</para>
+
+        <para>Example: if a system service unit has the following,
+        <programlisting>RuntimeDirectory=foo/bar
+StateDirectory=aaa/bbb ccc</programlisting>
+        then the environment variable <literal>RUNTIME_DIRECTORY</literal> is set with <literal>/run/foo/bar</literal>, and
+        <literal>STATE_DIRECTORY</literal> is set with <literal>/var/lib/aaa/bbb:/var/lib/ccc</literal>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 31af7cfa9835fdc25525e400d857d9f60bf29566..2c564d26b47858786b628dc478df828ef24562f6 100644 (file)
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
+          <listitem>
+            <para>A boolean that enforces DHCPv6 stateful mode when the 'Other information' bit is set in
+            Router Advertisement messages. By default setting only the 'O' bit in Router Advertisements
+            makes DHCPv6 request network information in a stateless manner using a two-message Information
+            Request and Information Reply message exchange.
+            <ulink url="https://tools.ietf.org/html/rfc7084">RFC 7084</ulink>, requirement WPD-4, updates
+            this behavior for a Customer Edge router so that stateful DHCPv6 Prefix Delegation is also
+            requested when only the 'O' bit is set in Router Advertisements. This option enables such a CE
+            behavior as it is impossible to automatically distinguish the intention of the 'O' bit otherwise.
+            By default this option is set to 'false', enable it if no prefixes are delegated when the device
+            should be acting as a CE router.</para>
+          </listitem>
+        </varlistentry>
+
       </variablelist>
     </refsect1>
 
index a97c5fcffc3f696dd779366607c1c400fa0bf041..c29f622143b67123bdb6e824905e584964e8f239 100644 (file)
@@ -270,12 +270,14 @@ pkgconfig = import('pkgconfig')
 check_compilation_sh = find_program('tools/meson-check-compilation.sh')
 meson_build_sh = find_program('tools/meson-build.sh')
 
-if get_option('tests') != 'false'
-        cxx = find_program('c++', required : false)
-        if cxx.found()
-                #  Used only for tests
-                add_languages('cpp')
-        endif
+want_tests = get_option('tests')
+slow_tests = want_tests != 'false' and get_option('slow-tests')
+install_tests = get_option('install-tests')
+
+cxx = find_program('c++', required : false)
+if cxx.found()
+        #  Used only for tests
+        add_languages('cpp')
 endif
 
 want_ossfuzz = get_option('oss-fuzz')
@@ -1198,7 +1200,6 @@ want_importd = get_option('importd')
 if want_importd != 'false'
         have = (conf.get('HAVE_LIBCURL') == 1 and
                 conf.get('HAVE_ZLIB') == 1 and
-                conf.get('HAVE_BZIP2') == 1 and
                 conf.get('HAVE_XZ') == 1 and
                 conf.get('HAVE_GCRYPT') == 1)
         if want_importd == 'true' and not have
@@ -1291,9 +1292,6 @@ conf.set10('ENABLE_NSS', enable_nss)
 
 conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesyncd'))
 
-want_tests = get_option('tests')
-install_tests = get_option('install-tests')
-slow_tests = get_option('slow-tests')
 tests = []
 fuzzers = []
 
@@ -1465,7 +1463,8 @@ test_dlopen = executable(
         test_dlopen_c,
         include_directories : includes,
         link_with : [libbasic],
-        dependencies : [libdl])
+        dependencies : [libdl],
+        build_by_default : want_tests != 'false')
 
 foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
                  ['systemd',    'ENABLE_NSS_SYSTEMD'],
@@ -1503,9 +1502,12 @@ foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
                                          'rm $DESTDIR@0@/libnss_@1@.so'
                                          .format(rootlibdir, module))
 
-                test('dlopen-nss_' + module,
-                     test_dlopen,
-                     args : [nss.full_path()]) # path to dlopen must include a slash
+                if want_tests != 'false'
+                        test('dlopen-nss_' + module,
+                             test_dlopen,
+                             # path to dlopen must include a slash
+                             args : nss.full_path())
+                endif
         endif
 endforeach
 
@@ -1746,9 +1748,12 @@ if conf.get('ENABLE_LOGIND') == 1
                         install : true,
                         install_dir : pamlibdir)
 
-                test('dlopen-pam_systemd',
-                     test_dlopen,
-                     args : [pam_systemd.full_path()]) # path to dlopen must include a slash
+                if want_tests != 'false'
+                        test('dlopen-pam_systemd',
+                             test_dlopen,
+                             # path to dlopen must include a slash
+                             args : pam_systemd.full_path())
+                endif
         endif
 endif
 
@@ -2435,10 +2440,12 @@ if conf.get('ENABLE_TMPFILES') == 1
                          install_dir : rootbindir)
         public_programs += exe
 
-        test('test-systemd-tmpfiles',
-             test_systemd_tmpfiles_py,
-             args : exe.full_path())
-        # https://github.com/mesonbuild/meson/issues/2681
+        if want_tests != 'false'
+                test('test-systemd-tmpfiles',
+                     test_systemd_tmpfiles_py,
+                     # https://github.com/mesonbuild/meson/issues/2681
+                     args : exe.full_path())
+        endif
 endif
 
 if conf.get('ENABLE_HWDB') == 1
@@ -2476,7 +2483,7 @@ public_programs += exe
 exe = executable('systemd-udevd',
                  systemd_udevd_sources,
                  include_directories : includes,
-                 c_args : ['-DLOG_REALM=LOG_REALM_UDEV'],
+                 c_args : '-DLOG_REALM=LOG_REALM_UDEV',
                  link_with : [libudev_core,
                               libsystemd_network,
                               libudev_static],
@@ -2492,7 +2499,7 @@ public_programs += exe
 
 exe = executable('udevadm',
                  udevadm_sources,
-                 c_args : ['-DLOG_REALM=LOG_REALM_UDEV'],
+                 c_args : '-DLOG_REALM=LOG_REALM_UDEV',
                  include_directories : includes,
                  link_with : [libudev_core,
                               libsystemd_network,
@@ -2630,9 +2637,8 @@ foreach tuple : tests
                 timeout = type.split('=')[1].to_int()
                 type = ''
         endif
-        if want_tests == 'false'
-                message('Not compiling @0@ because tests is set to false'.format(name))
-        elif condition == '' or conf.get(condition) == 1
+
+        if condition == '' or conf.get(condition) == 1
                 exe = executable(
                         name,
                         sources,
@@ -2640,6 +2646,7 @@ foreach tuple : tests
                         link_with : link_with,
                         dependencies : dependencies,
                         c_args : defs,
+                        build_by_default : want_tests != 'false',
                         install_rpath : rootlibexecdir,
                         install : install_tests,
                         install_dir : join_paths(testsdir, type))
@@ -2648,7 +2655,7 @@ foreach tuple : tests
                         message('@0@ is a manual test'.format(name))
                 elif type == 'unsafe' and want_tests != 'unsafe'
                         message('@0@ is an unsafe test'.format(name))
-                else
+                elif want_tests != 'false'
                         test(name, exe,
                              env : test_env,
                              timeout : timeout)
@@ -2663,9 +2670,12 @@ exe = executable(
         test_libsystemd_sym_c,
         include_directories : includes,
         link_with : [libsystemd],
+        build_by_default : want_tests != 'false',
         install : install_tests,
         install_dir : testsdir)
-test('test-libsystemd-sym', exe)
+if want_tests != 'false'
+        test('test-libsystemd-sym', exe)
+endif
 
 exe = executable(
         'test-libsystemd-static-sym',
@@ -2674,10 +2684,10 @@ exe = executable(
         link_with : [install_libsystemd_static],
         dependencies : [threads], # threads is already included in dependencies on the library,
                                   # but does not seem to get propagated. Add here as a work-around.
-        build_by_default : static_libsystemd_pic,
+        build_by_default : want_tests != 'false' and static_libsystemd_pic,
         install : install_tests and static_libsystemd_pic,
         install_dir : testsdir)
-if static_libsystemd_pic
+if want_tests != 'false' and static_libsystemd_pic
         test('test-libsystemd-static-sym', exe)
 endif
 
@@ -2685,22 +2695,25 @@ exe = executable(
         'test-libudev-sym',
         test_libudev_sym_c,
         include_directories : includes,
-        c_args : ['-Wno-deprecated-declarations'],
+        c_args : '-Wno-deprecated-declarations',
         link_with : [libudev],
+        build_by_default : want_tests != 'false',
         install : install_tests,
         install_dir : testsdir)
-test('test-libudev-sym', exe)
+if want_tests != 'false'
+        test('test-libudev-sym', exe)
+endif
 
 exe = executable(
         'test-libudev-static-sym',
         test_libudev_sym_c,
         include_directories : includes,
-        c_args : ['-Wno-deprecated-declarations'],
+        c_args : '-Wno-deprecated-declarations',
         link_with : [install_libudev_static],
-        build_by_default : static_libudev_pic,
+        build_by_default : want_tests != 'false' and static_libudev_pic,
         install : install_tests and static_libudev_pic,
         install_dir : testsdir)
-if static_libudev_pic
+if want_tests != 'false' and static_libudev_pic
         test('test-libudev-static-sym', exe)
 endif
 
@@ -2790,9 +2803,11 @@ meson_check_help = find_program('tools/meson-check-help.sh')
 
 foreach exec : public_programs
         name = exec.full_path().split('/')[-1]
-        test('check-help-' + name,
-             meson_check_help,
-             args : [exec.full_path()])
+        if want_tests != 'false'
+                test('check-help-' + name,
+                     meson_check_help,
+                     args : exec.full_path())
+        endif
 endforeach
 
 ############################################################
index e2d22afe51b40cd7e8f042b213f0fbb4737f66dd..54dd7de105d865cc5281e4807fabffd888ddeb83 100644 (file)
@@ -41,8 +41,6 @@
 #define SCALE_X (0.1 / 1000.0)   /* pixels per us */
 #define SCALE_Y (20.0)
 
-#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
-
 #define svg(...) printf(__VA_ARGS__)
 
 #define svg_bar(class, x1, x2, y)                                       \
@@ -191,14 +189,12 @@ static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char
         return 0;
 }
 
-static int compare_unit_time(const void *a, const void *b) {
-        return compare(((struct unit_times *)b)->time,
-                       ((struct unit_times *)a)->time);
+static int compare_unit_time(const struct unit_times *a, const struct unit_times *b) {
+        return CMP(b->time, a->time);
 }
 
-static int compare_unit_start(const void *a, const void *b) {
-        return compare(((struct unit_times *)a)->activating,
-                       ((struct unit_times *)b)->activating);
+static int compare_unit_start(const struct unit_times *a, const struct unit_times *b) {
+        return CMP(a->activating, b->activating);
 }
 
 static void unit_times_free(struct unit_times *t) {
@@ -629,7 +625,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
         if (n <= 0)
                 return n;
 
-        qsort(times, n, sizeof(struct unit_times), compare_unit_start);
+        typesafe_qsort(times, n, compare_unit_start);
 
         width = SCALE_X * (boot->firmware_time + boot->finish_time);
         if (width < 800.0)
@@ -854,8 +850,7 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
 
 static Hashmap *unit_times_hashmap;
 
-static int list_dependencies_compare(const void *_a, const void *_b) {
-        const char **a = (const char**) _a, **b = (const char**) _b;
+static int list_dependencies_compare(char * const *a, char * const *b) {
         usec_t usa = 0, usb = 0;
         struct unit_times *times;
 
@@ -866,7 +861,7 @@ static int list_dependencies_compare(const void *_a, const void *_b) {
         if (times)
                 usb = times->activated;
 
-        return usb - usa;
+        return CMP(usb, usa);
 }
 
 static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) {
@@ -891,7 +886,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
         if (r < 0)
                 return r;
 
-        qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+        typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
 
         r = acquire_boot_times(bus, &boot);
         if (r < 0)
@@ -1056,7 +1051,7 @@ static int analyze_blame(int argc, char *argv[], void *userdata) {
         if (n <= 0)
                 return n;
 
-        qsort(times, n, sizeof(struct unit_times), compare_unit_time);
+        typesafe_qsort(times, n, compare_unit_time);
 
         (void) pager_open(arg_no_pager, false);
 
index c9d45c22531dd2ef21623e89c611b1ed9dcd59b8..fb8e3742e87757f1d85c35418ec97537b3dd3cf0 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "alloc-util.h"
 #include "def.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
 #include "escape.h"
 #include "fileio.h"
 #include "mkdir.h"
@@ -88,7 +88,7 @@ static int same_device(sd_device *a, sd_device *b) {
         if (r < 0)
                 return r;
 
-        if (!streq_ptr(a_val, b_val))
+        if (!streq(a_val, b_val))
                 return false;
 
         r = sd_device_get_sysname(a, &a_val);
@@ -99,7 +99,7 @@ static int same_device(sd_device *a, sd_device *b) {
         if (r < 0)
                 return r;
 
-        return streq_ptr(a_val, b_val);
+        return streq(a_val, b_val);
 }
 
 static int validate_device(sd_device *device) {
@@ -156,11 +156,7 @@ static int validate_device(sd_device *device) {
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(enumerate);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(enumerate, other) {
+        FOREACH_DEVICE(enumerate, other) {
                 const char *other_subsystem;
                 sd_device *other_parent;
 
index 376844b7b17f9e0c3e0c76aa1b849fb76a0d8fd8..0308048b7f8da9c49026d6d6e66d8f0a38d541af 100644 (file)
@@ -877,7 +877,7 @@ int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, u
 
 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
         struct btrfs_ioctl_vol_args args = {};
-        char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")];
+        char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")], q[DEV_NUM_PATH_MAX];
         _cleanup_free_ char *backing = NULL;
         _cleanup_close_ int loop_fd = -1, backing_fd = -1;
         struct stat st;
@@ -922,8 +922,8 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
         if (grow_only && new_size < (uint64_t) st.st_size)
                 return -EINVAL;
 
-        xsprintf_sys_block_path(p, NULL, dev);
-        loop_fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY);
+        xsprintf_dev_num_path(q, "block", dev);
+        loop_fd = open(q, O_RDWR|O_CLOEXEC|O_NOCTTY);
         if (loop_fd < 0)
                 return -errno;
 
index 8cb645aeace1d853340de36028961b007de85dd5..dafc09e8f84913ff1dc870a05816731a758f3411 100644 (file)
@@ -57,25 +57,18 @@ CalendarSpec* calendar_spec_free(CalendarSpec *c) {
         return mfree(c);
 }
 
-static int component_compare(const void *_a, const void *_b) {
-        CalendarComponent * const *a = _a, * const *b = _b;
-
-        if ((*a)->start < (*b)->start)
-                return -1;
-        if ((*a)->start > (*b)->start)
-                return 1;
+static int component_compare(CalendarComponent * const *a, CalendarComponent * const *b) {
+        int r;
 
-        if ((*a)->stop < (*b)->stop)
-                return -1;
-        if ((*a)->stop > (*b)->stop)
-                return 1;
+        r = CMP((*a)->start, (*b)->start);
+        if (r != 0)
+                return r;
 
-        if ((*a)->repeat < (*b)->repeat)
-                return -1;
-        if ((*a)->repeat > (*b)->repeat)
-                return 1;
+        r = CMP((*a)->stop, (*b)->stop);
+        if (r != 0)
+                return r;
 
-        return 0;
+        return CMP((*a)->repeat, (*b)->repeat);
 }
 
 static void normalize_chain(CalendarComponent **c) {
@@ -103,7 +96,7 @@ static void normalize_chain(CalendarComponent **c) {
         for (i = *c; i; i = i->next)
                 *(j++) = i;
 
-        qsort(b, n, sizeof(CalendarComponent*), component_compare);
+        typesafe_qsort(b, n, component_compare);
 
         b[n-1]->next = NULL;
         next = b[n-1];
index d6ef0e941e1d1a9a821a63e091232aaf3732bf0e..d03366077d7c7b95b6660593ee8d2e03ed1d91a3 100644 (file)
@@ -134,12 +134,8 @@ static int files_add(
         return 0;
 }
 
-static int base_cmp(const void *a, const void *b) {
-        const char *s1, *s2;
-
-        s1 = *(char * const *)a;
-        s2 = *(char * const *)b;
-        return strcmp(basename(s1), basename(s2));
+static int base_cmp(char * const *a, char * const *b) {
+        return strcmp(basename(*a), basename(*b));
 }
 
 static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, unsigned flags, char **dirs) {
@@ -176,7 +172,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
         if (!files)
                 return -ENOMEM;
 
-        qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
+        typesafe_qsort(files, hashmap_size(fh), base_cmp);
         *strv = files;
 
         return 0;
@@ -200,7 +196,7 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p
         for (i = 0; i < strv_length(*strv); i++) {
                 int c;
 
-                c = base_cmp(*strv + i, &path);
+                c = base_cmp((char* const*) *strv + i, (char* const*) &path);
                 if (c == 0) {
                         char **dir;
 
index 7e336f9ce1ef3f200387cfb992818e75378ae138..e8af191104f535ee1e56133599d460a4ad690750 100644 (file)
@@ -71,11 +71,12 @@ static int do_execute(
                 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
                 void* const callback_args[_STDOUT_CONSUME_MAX],
                 int output_fd,
-                char *argv[]) {
+                char *argv[],
+                char *envp[]) {
 
         _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
         _cleanup_strv_free_ char **paths = NULL;
-        char **path;
+        char **path, **e;
         int r;
 
         /* We fork this all off from a child process so that we can somewhat cleanly make
@@ -100,6 +101,9 @@ static int do_execute(
         if (timeout != USEC_INFINITY)
                 alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));
 
+        STRV_FOREACH(e, envp)
+                putenv(*e);
+
         STRV_FOREACH(path, paths) {
                 _cleanup_free_ char *t = NULL;
                 _cleanup_close_ int fd = -1;
@@ -166,7 +170,8 @@ int execute_directories(
                 usec_t timeout,
                 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
                 void* const callback_args[_STDOUT_CONSUME_MAX],
-                char *argv[]) {
+                char *argv[],
+                char *envp[]) {
 
         char **dirs = (char**) directories;
         _cleanup_close_ int fd = -1;
@@ -197,7 +202,7 @@ int execute_directories(
         if (r < 0)
                 return r;
         if (r == 0) {
-                r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv);
+                r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp);
                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
         }
 
index 823ca6578cf5b0c6b07fffea2b5f17282ef53adf..6ac3c9000a048ceff99ca4d49a7158069b48cdb8 100644 (file)
@@ -19,6 +19,7 @@ int execute_directories(
                 usec_t timeout,
                 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
                 void* const callback_args[_STDOUT_CONSUME_MAX],
-                char *argv[]);
+                char *argv[],
+                char *envp[]);
 
 extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
index 8ef278248d55bd9b337d01964a71fbf71d4bb5be..e30460eab6248f8ec727ad0c8292af72b9d1e88a 100644 (file)
@@ -729,9 +729,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
         return 0;
 }
 
-static int table_data_compare(const void *x, const void *y, void *userdata) {
-        const size_t *a = x, *b = y;
-        Table *t = userdata;
+static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
         size_t i;
         int r;
 
@@ -759,12 +757,7 @@ static int table_data_compare(const void *x, const void *y, void *userdata) {
         }
 
         /* Order identical lines by the order there were originally added in */
-        if (*a < *b)
-                return -1;
-        if (*a > *b)
-                return 1;
-
-        return 0;
+        return CMP(*a, *b);
 }
 
 static const char *table_data_format(TableData *d) {
@@ -944,7 +937,7 @@ int table_print(Table *t, FILE *f) {
                 for (i = 0; i < n_rows; i++)
                         sorted[i] = i * t->n_columns;
 
-                qsort_r_safe(sorted, n_rows, sizeof(size_t), table_data_compare, t);
+                typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
         }
 
         if (t->display_map)
index 09fcc32e0ef51c4a102f9b1f2971f6da70d7b9f7..1fa76bda3de92d6ce4d4d3030229a5937b8f0015 100644 (file)
@@ -346,12 +346,27 @@ int touch(const char *path) {
         return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
 }
 
-int symlink_idempotent(const char *from, const char *to) {
+int symlink_idempotent(const char *from, const char *to, bool make_relative) {
+        _cleanup_free_ char *relpath = NULL;
         int r;
 
         assert(from);
         assert(to);
 
+        if (make_relative) {
+                _cleanup_free_ char *parent = NULL;
+
+                parent = dirname_malloc(to);
+                if (!parent)
+                        return -ENOMEM;
+
+                r = path_make_relative(parent, from, &relpath);
+                if (r < 0)
+                        return r;
+
+                from = relpath;
+        }
+
         if (symlink(from, to) < 0) {
                 _cleanup_free_ char *p = NULL;
 
index 4b65625861af310161f8ef89d49fbcfe32b18ee1..bc753d5920699b84558e24aa526e4f2e897a51a9 100644 (file)
@@ -37,7 +37,7 @@ int fd_warn_permissions(const char *path, int fd);
 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
 int touch(const char *path);
 
-int symlink_idempotent(const char *from, const char *to);
+int symlink_idempotent(const char *from, const char *to, bool make_relative);
 
 int symlink_atomic(const char *from, const char *to);
 int mknod_atomic(const char *path, mode_t mode, dev_t dev);
index 1f9590ccb6a266f99140126c38336996cf1925b8..ae62d3090e7218bd0589366071abc238f92121bd 100644 (file)
@@ -951,3 +951,39 @@ int mount_option_mangle(
 
         return 0;
 }
+
+int dev_is_devtmpfs(void) {
+        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+        char line[LINE_MAX], *e;
+        int mount_id, r;
+
+        r = path_get_mnt_id("/dev", &mount_id);
+        if (r < 0)
+                return r;
+
+        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+        if (!proc_self_mountinfo)
+                return -errno;
+
+        (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
+
+        FOREACH_LINE(line, proc_self_mountinfo, return -errno) {
+                int mid;
+
+                if (sscanf(line, "%i", &mid) != 1)
+                        continue;
+
+                if (mid != mount_id)
+                        continue;
+
+                e = strstr(line, " - ");
+                if (!e)
+                        continue;
+
+                /* accept any name that starts with the currently expected type */
+                if (startswith(e + 3, "devtmpfs"))
+                        return true;
+        }
+
+        return false;
+}
index 3cfea3bb20d1a0a9b786e7dfe65208f6be2322ac..ad8c47cb325f89b97ecbc3b08dbe31b557d2754b 100644 (file)
@@ -54,3 +54,5 @@ int mount_option_mangle(
                 unsigned long mount_flags,
                 unsigned long *ret_mount_flags,
                 char **ret_remaining_options);
+
+int dev_is_devtmpfs(void);
index d6ee8b62b81272e677b123d9c18d1eb65e52682b..c887f9708b3661794dd05ab14d8a92407d52f5cc 100644 (file)
@@ -1104,11 +1104,9 @@ void valgrind_summary_hack(void) {
 #endif
 }
 
-int pid_compare_func(const void *a, const void *b) {
-        const pid_t *p = a, *q = b;
-
+int pid_compare_func(const pid_t *a, const pid_t *b) {
         /* Suitable for usage in qsort() */
-        return CMP(*p, *q);
+        return CMP(*a, *b);
 }
 
 int ioprio_parse_priority(const char *s, int *ret) {
index a5bb072b25357325f22c6755e3391cd429190ec9..7ef45dc92b867a7c193bab6b1d05e21cfa9fb6cb 100644 (file)
@@ -108,7 +108,7 @@ static inline void* PID_TO_PTR(pid_t pid) {
 
 void valgrind_summary_hack(void);
 
-int pid_compare_func(const void *a, const void *b);
+int pid_compare_func(const pid_t *a, const pid_t *b);
 
 static inline bool nice_is_valid(int n) {
         return n >= PRIO_MIN && n < PRIO_MAX;
index 275a012b28a54e20b9183e3a2556f000c977c5cb..81f4f21ade34562c173f6b5fc1fe948b6aea6856 100644 (file)
@@ -142,9 +142,7 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
 
                 /* lookup child node */
                 search.c = c;
-                child = bsearch_safe(&search, node->children, node->children_count,
-                                     sizeof(struct strbuf_child_entry),
-                                     (__compar_fn_t) strbuf_children_cmp);
+                child = typesafe_bsearch(&search, node->children, node->children_count, strbuf_children_cmp);
                 if (!child)
                         break;
                 node = child->child;
index abf3fc4c7bd9bc5fb38e030d981500432126cc5d..dc72f036ac90343943def1c98bf338855d1482b8 100644 (file)
@@ -339,21 +339,22 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
         return (int) n;
 }
 
-char *strv_join(char **l, const char *separator) {
+char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
         char *r, *e;
         char **s;
-        size_t n, k;
+        size_t n, k, m;
 
         if (!separator)
                 separator = " ";
 
         k = strlen(separator);
+        m = strlen_ptr(prefix);
 
         n = 0;
         STRV_FOREACH(s, l) {
                 if (s != l)
                         n += k;
-                n += strlen(*s);
+                n += m + strlen(*s);
         }
 
         r = new(char, n+1);
@@ -365,6 +366,9 @@ char *strv_join(char **l, const char *separator) {
                 if (s != l)
                         e = stpcpy(e, separator);
 
+                if (prefix)
+                        e = stpcpy(e, prefix);
+
                 e = stpcpy(e, *s);
         }
 
@@ -711,14 +715,12 @@ bool strv_overlap(char **a, char **b) {
         return false;
 }
 
-static int str_compare(const void *_a, const void *_b) {
-        const char **a = (const char**) _a, **b = (const char**) _b;
-
+static int str_compare(char * const *a, char * const *b) {
         return strcmp(*a, *b);
 }
 
 char **strv_sort(char **l) {
-        qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
+        typesafe_qsort(l, strv_length(l), str_compare);
         return l;
 }
 
index 51d03db9403d03e08200096429fd5465690b0cbe..34a660cb920037286fa24135de772655bc943e1d 100644 (file)
@@ -71,7 +71,10 @@ char **strv_split_newlines(const char *s);
 
 int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
 
-char *strv_join(char **l, const char *separator);
+char *strv_join_prefix(char **l, const char *separator, const char *prefix);
+static inline char *strv_join(char **l, const char *separator) {
+        return strv_join_prefix(l, separator, NULL);
+}
 
 char **strv_parse_nulstr(const char *s, size_t l);
 char **strv_split_nulstr(const char *s);
index f951d641d70dc9eccc785d6e15df8cb1f2824e91..081c63c898c12318a3c7379e82a3ddf33710d21a 100644 (file)
@@ -133,7 +133,7 @@ void in_initrd_force(bool value) {
 
 /* hey glibc, APIs with callbacks without a user pointer are so useless */
 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
-                 int (*compar) (const void *, const void *, void *), void *arg) {
+                 __compar_d_fn_t compar, void *arg) {
         size_t l, u, idx;
         const void *p;
         int comparison;
index 308933ac90ba42703ff957acd52bf68accab9ecb..5f3f982190214381b892f677e9aa304de165042b 100644 (file)
@@ -68,15 +68,21 @@ bool in_initrd(void);
 void in_initrd_force(bool value);
 
 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
-                 int (*compar) (const void *, const void *, void *),
-                 void *arg);
+                 __compar_d_fn_t compar, void *arg);
+
+#define typesafe_bsearch_r(k, b, n, func, userdata)                     \
+        ({                                                              \
+                const typeof(b[0]) *_k = k;                             \
+                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
+                xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
+        })
 
 /**
  * Normal bsearch requires base to be nonnull. Here were require
  * that only if nmemb > 0.
  */
 static inline void* bsearch_safe(const void *key, const void *base,
-                                 size_t nmemb, size_t size, comparison_fn_t compar) {
+                                 size_t nmemb, size_t size, __compar_fn_t compar) {
         if (nmemb <= 0)
                 return NULL;
 
@@ -84,11 +90,18 @@ static inline void* bsearch_safe(const void *key, const void *base,
         return bsearch(key, base, nmemb, size, compar);
 }
 
+#define typesafe_bsearch(k, b, n, func)                                 \
+        ({                                                              \
+                const typeof(b[0]) *_k = k;                             \
+                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
+                bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
+        })
+
 /**
  * Normal qsort requires base to be nonnull. Here were require
  * that only if nmemb > 0.
  */
-static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
         if (nmemb <= 1)
                 return;
 
@@ -104,7 +117,7 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_
                 qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
         })
 
-static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void *userdata) {
+static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
         if (nmemb <= 1)
                 return;
 
@@ -112,6 +125,12 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*com
         qsort_r(base, nmemb, size, compar, userdata);
 }
 
+#define typesafe_qsort_r(p, n, func, userdata)                          \
+        ({                                                              \
+                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
+                qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
+        })
+
 /* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
 static inline void memcpy_safe(void *dst, const void *src, size_t n) {
         if (n == 0)
index 1893ea37339d53455f4e8beca6933feba7d8b554..34c7708080499f5568e8082505ce20cda63d6f88 100644 (file)
@@ -59,7 +59,9 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
         assert(argc >= optind);
 
         left = argc - optind;
-        name = argv[optind];
+        argv += optind;
+        optind = 0;
+        name = argv[0];
 
         for (i = 0;; i++) {
                 bool found;
@@ -116,7 +118,7 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
         }
 
         if (name)
-                return verb->dispatch(left, argv + optind, userdata);
+                return verb->dispatch(left, argv, userdata);
         else {
                 char* fake[2] = {
                         (char*) verb->verb,
index d347732bb3da41f002678f4ecd249b1734086983..e05b3e6d990c5d7b0210b698b5dd7fba64244e29 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "alloc-util.h"
 #include "dirent-util.h"
+#include "def.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -259,21 +260,38 @@ static int detect_vm_hypervisor(void) {
 }
 
 static int detect_vm_uml(void) {
-        _cleanup_free_ char *cpuinfo_contents = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         /* Detect User-Mode Linux by reading /proc/cpuinfo */
-        r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
-        if (r == -ENOENT) {
-                log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
-                return VIRTUALIZATION_NONE;
+        f = fopen("/proc/cpuinfo", "re");
+        if (!f) {
+                if (errno == ENOENT) {
+                        log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
+                        return VIRTUALIZATION_NONE;
+                }
+                return -errno;
         }
-        if (r < 0)
-                return r;
 
-        if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
-                log_debug("UML virtualization found in /proc/cpuinfo");
-                return VIRTUALIZATION_UML;
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                const char *t;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                t = startswith(line, "vendor_id\t: ");
+                if (t) {
+                        if (startswith(t, "User Mode Linux")) {
+                                log_debug("UML virtualization found in /proc/cpuinfo");
+                                return VIRTUALIZATION_UML;
+                        }
+
+                        break;
+                }
         }
 
         log_debug("UML virtualization not found in /proc/cpuinfo.");
index 1cec5505a0534b218254a1dd27e339064783e2b8..c5509e73d19b7a64f2b434f68c063bfd4714313d 100644 (file)
@@ -169,9 +169,11 @@ if have_gnu_efi
                                   efi_ldflags + tuple[2] +
                                   ['-lefi', '-lgnuefi', libgcc_file_name])
 
-                test('no-undefined-symbols-' + tuple[0],
-                     no_undefined_symbols,
-                     args : [so])
+                if want_tests != 'false'
+                        test('no-undefined-symbols-' + tuple[0],
+                             no_undefined_symbols,
+                             args : [so])
+                endif
 
                 stub = custom_target(
                         tuple[1],
index 9dc522ad1896e2b549db48d2b481c64a86b26026..7b651cfcd690fba568f6f0ac864aefa486d0e045 100644 (file)
@@ -719,8 +719,7 @@ static void member_hash_func(const void *p, struct siphash *state) {
                 string_hash_func(m->interface, state);
 }
 
-static int member_compare_func(const void *a, const void *b) {
-        const Member *x = a, *y = b;
+static int member_compare_func(const Member *x, const Member *y) {
         int d;
 
         assert(x);
@@ -739,10 +738,8 @@ static int member_compare_func(const void *a, const void *b) {
         return strcmp_ptr(x->name, y->name);
 }
 
-static int member_compare_funcp(const void *a, const void *b) {
-        const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
-
-        return member_compare_func(*x, *y);
+static int member_compare_funcp(Member * const *a, Member * const *b) {
+        return member_compare_func(*a, *b);
 }
 
 static void member_free(Member *m) {
@@ -913,7 +910,7 @@ static int on_property(const char *interface, const char *name, const char *sign
 static int introspect(int argc, char **argv, void *userdata) {
         static const struct hash_ops member_hash_ops = {
                 .hash = member_hash_func,
-                .compare = member_compare_func,
+                .compare = (__compar_fn_t) member_compare_func,
         };
 
         static const XMLIntrospectOps ops = {
@@ -1063,7 +1060,7 @@ static int introspect(int argc, char **argv, void *userdata) {
         if (result_width > 40)
                 result_width = 40;
 
-        qsort(sorted, k, sizeof(Member*), member_compare_funcp);
+        typesafe_qsort(sorted, k, member_compare_funcp);
 
         if (arg_legend) {
                 printf("%-*s %-*s %-*s %-*s %s\n",
index cd338cbb313cf86b39bec4e189ff40cc8431057c..1976d9959778a0b467fd0c9a8ceef1a3558cec46 100644 (file)
@@ -524,8 +524,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration)
         return 0;
 }
 
-static int group_compare(const void*a, const void *b) {
-        const Group *x = *(Group**)a, *y = *(Group**)b;
+static int group_compare(Group * const *a, Group * const *b) {
+        const Group *x = *a, *y = *b;
+        int r;
 
         if (arg_order != ORDER_TASKS || arg_recursive) {
                 /* Let's make sure that the parent is always before
@@ -547,29 +548,26 @@ static int group_compare(const void*a, const void *b) {
         case ORDER_CPU:
                 if (arg_cpu_type == CPU_PERCENT) {
                         if (x->cpu_valid && y->cpu_valid) {
-                                if (x->cpu_fraction > y->cpu_fraction)
-                                        return -1;
-                                else if (x->cpu_fraction < y->cpu_fraction)
-                                        return 1;
+                                r = CMP(y->cpu_fraction, x->cpu_fraction);
+                                if (r != 0)
+                                        return r;
                         } else if (x->cpu_valid)
                                 return -1;
                         else if (y->cpu_valid)
                                 return 1;
                 } else {
-                        if (x->cpu_usage > y->cpu_usage)
-                                return -1;
-                        else if (x->cpu_usage < y->cpu_usage)
-                                return 1;
+                        r = CMP(y->cpu_usage, x->cpu_usage);
+                        if (r != 0)
+                                return r;
                 }
 
                 break;
 
         case ORDER_TASKS:
                 if (x->n_tasks_valid && y->n_tasks_valid) {
-                        if (x->n_tasks > y->n_tasks)
-                                return -1;
-                        else if (x->n_tasks < y->n_tasks)
-                                return 1;
+                        r = CMP(y->n_tasks, x->n_tasks);
+                        if (r != 0)
+                                return r;
                 } else if (x->n_tasks_valid)
                         return -1;
                 else if (y->n_tasks_valid)
@@ -579,10 +577,9 @@ static int group_compare(const void*a, const void *b) {
 
         case ORDER_MEMORY:
                 if (x->memory_valid && y->memory_valid) {
-                        if (x->memory > y->memory)
-                                return -1;
-                        else if (x->memory < y->memory)
-                                return 1;
+                        r = CMP(y->memory, x->memory);
+                        if (r != 0)
+                                return r;
                 } else if (x->memory_valid)
                         return -1;
                 else if (y->memory_valid)
@@ -592,10 +589,9 @@ static int group_compare(const void*a, const void *b) {
 
         case ORDER_IO:
                 if (x->io_valid && y->io_valid) {
-                        if (x->io_input_bps + x->io_output_bps > y->io_input_bps + y->io_output_bps)
-                                return -1;
-                        else if (x->io_input_bps + x->io_output_bps < y->io_input_bps + y->io_output_bps)
-                                return 1;
+                        r = CMP(y->io_input_bps + y->io_output_bps, x->io_input_bps + x->io_output_bps);
+                        if (r != 0)
+                                return r;
                 } else if (x->io_valid)
                         return -1;
                 else if (y->io_valid)
@@ -624,7 +620,7 @@ static void display(Hashmap *a) {
                 if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid)
                         array[n++] = g;
 
-        qsort_safe(array, n, sizeof(Group*), group_compare);
+        typesafe_qsort(array, n, group_compare);
 
         /* Find the longest names in one run */
         for (j = 0; j < n; j++) {
index 187fed12b2c7f7dee7c5ef81ceec8a0c0f23ae07..721b4bc9ce78ed1adddb435e60c745dcb03ea561 100644 (file)
@@ -660,7 +660,7 @@ int bpf_firewall_supported(void) {
          * b) whether the unified hierarchy is being used
          * c) the BPF implementation in the kernel supports BPF LPM TRIE maps, which we require
          * d) the BPF implementation in the kernel supports BPF_PROG_TYPE_CGROUP_SKB programs, which we require
-         * e) the BPF implementation in the kernel supports the BPF_PROG_ATTACH call, which we require
+         * e) the BPF implementation in the kernel supports the BPF_PROG_DETACH call, which we require
          */
 
         if (supported >= 0)
@@ -713,7 +713,7 @@ int bpf_firewall_supported(void) {
          * is turned off at kernel compilation time. This sucks of course: why does it allow us to create a cgroup BPF
          * program if we can't do a thing with it later?
          *
-         * We detect this case by issuing the BPF_PROG_ATTACH bpf() call with invalid file descriptors: if
+         * We detect this case by issuing the BPF_PROG_DETACH bpf() call with invalid file descriptors: if
          * CONFIG_CGROUP_BPF is turned off, then the call will fail early with EINVAL. If it is turned on the
          * parameters are validated however, and that'll fail with EBADF then. */
 
@@ -723,22 +723,22 @@ int bpf_firewall_supported(void) {
                 .attach_bpf_fd = -1,
         };
 
-        if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
+        if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
                 if (errno != EBADF) {
-                        log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_ATTACH, BPF firewalling is not supported: %m");
+                        log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m");
                         return supported = BPF_FIREWALL_UNSUPPORTED;
                 }
 
                 /* YAY! */
         } else {
-                log_debug("Wut? Kernel accepted our invalid BPF_PROG_ATTACH call? Something is weird, assuming BPF firewalling is broken and hence not supported.");
+                log_debug("Wut? Kernel accepted our invalid BPF_PROG_DETACH call? Something is weird, assuming BPF firewalling is broken and hence not supported.");
                 return supported = BPF_FIREWALL_UNSUPPORTED;
         }
 
         /* So now we know that the BPF program is generally available, let's see if BPF_F_ALLOW_MULTI is also supported
-         * (which was added in kernel 4.15). We use a similar logic as before, but this time we use
-         * BPF_F_ALLOW_MULTI. Since the flags are checked early in the system call we'll get EINVAL if it's not
-         * supported, and EBADF as before if it is available. */
+         * (which was added in kernel 4.15). We use a similar logic as before, but this time we use the BPF_PROG_ATTACH
+         * bpf() call and the BPF_F_ALLOW_MULTI flags value. Since the flags are checked early in the system call we'll
+         * get EINVAL if it's not supported, and EBADF as before if it is available. */
 
         attr = (union bpf_attr) {
                 .attach_type = BPF_CGROUP_INET_EGRESS,
index c8c8472ea4fb6b77890505393a4bf90bc1420d5c..634a45592f0cc2cc4b1f83ccdd021241fd6a3b8a 100644 (file)
@@ -7,7 +7,6 @@
 #include "bus-error.h"
 #include "dbus-device.h"
 #include "device-private.h"
-#include "device-enumerator-private.h"
 #include "device-util.h"
 #include "device.h"
 #include "libudev-private.h"
@@ -831,13 +830,7 @@ static void device_enumerate(Manager *m) {
                 goto fail;
         }
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0) {
-                log_error_errno(r, "Failed to enumerate devices: %m");
-                goto fail;
-        }
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, dev) {
+        FOREACH_DEVICE(e, dev) {
                 const char *sysfs;
 
                 if (!device_is_ready(dev))
index 501b367eae9e3697ecef2b60007b337821d8b6b0..9be95c96ae3011f1cfbe0c46bbc3eccb51068532 100644 (file)
@@ -1602,6 +1602,8 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
         idle_pipe[3] = safe_close(idle_pipe[3]);
 }
 
+static const char *exec_directory_env_name_to_string(ExecDirectoryType t);
+
 static int build_environment(
                 const Unit *u,
                 const ExecContext *c,
@@ -1615,14 +1617,16 @@ static int build_environment(
                 char ***ret) {
 
         _cleanup_strv_free_ char **our_env = NULL;
+        ExecDirectoryType t;
         size_t n_env = 0;
         char *x;
 
         assert(u);
         assert(c);
+        assert(p);
         assert(ret);
 
-        our_env = new0(char*, 14);
+        our_env = new0(char*, 14 + _EXEC_DIRECTORY_TYPE_MAX);
         if (!our_env)
                 return -ENOMEM;
 
@@ -1727,8 +1731,37 @@ static int build_environment(
                 our_env[n_env++] = x;
         }
 
+        for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+                _cleanup_free_ char *pre = NULL, *joined = NULL;
+                const char *n;
+
+                if (!p->prefix[t])
+                        continue;
+
+                if (strv_isempty(c->directories[t].paths))
+                        continue;
+
+                n = exec_directory_env_name_to_string(t);
+                if (!n)
+                        continue;
+
+                pre = strjoin(p->prefix[t], "/");
+                if (!pre)
+                        return -ENOMEM;
+
+                joined = strv_join_prefix(c->directories[t].paths, ":", pre);
+                if (!joined)
+                        return -ENOMEM;
+
+                x = strjoin(n, "=", joined);
+                if (!x)
+                        return -ENOMEM;
+
+                our_env[n_env++] = x;
+        }
+
         our_env[n_env++] = NULL;
-        assert(n_env <= 12);
+        assert(n_env <= 14 + _EXEC_DIRECTORY_TYPE_MAX);
 
         *ret = TAKE_PTR(our_env);
 
@@ -2027,7 +2060,7 @@ static int setup_exec_directory(
 
                 if (context->dynamic_user &&
                     !IN_SET(type, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)) {
-                        _cleanup_free_ char *private_root = NULL, *relative = NULL, *parent = NULL;
+                        _cleanup_free_ char *private_root = NULL;
 
                         /* So, here's one extra complication when dealing with DynamicUser=1 units. In that case we
                          * want to avoid leaving a directory around fully accessible that is owned by a dynamic user
@@ -2092,18 +2125,8 @@ static int setup_exec_directory(
                                         goto fail;
                         }
 
-                        parent = dirname_malloc(p);
-                        if (!parent) {
-                                r = -ENOMEM;
-                                goto fail;
-                        }
-
-                        r = path_make_relative(parent, pp, &relative);
-                        if (r < 0)
-                                goto fail;
-
                         /* And link it up from the original place */
-                        r = symlink_idempotent(relative, p);
+                        r = symlink_idempotent(pp, p, true);
                         if (r < 0)
                                 goto fail;
 
@@ -2400,12 +2423,16 @@ static int apply_mount_namespace(
          * that with a special, recognizable error ENOANO. In this case, silently proceeed, but only if exclusively
          * sandboxing options were used, i.e. nothing such as RootDirectory= or BindMount= that would result in a
          * completely different execution environment. */
-        if (r == -ENOANO &&
-            n_bind_mounts == 0 && context->n_temporary_filesystems == 0 &&
-            !root_dir && !root_image &&
-            !context->dynamic_user) {
-                log_unit_debug(u, "Failed to set up namespace, assuming containerized execution and ignoring.");
-                return 0;
+        if (r == -ENOANO) {
+                if (n_bind_mounts == 0 &&
+                    context->n_temporary_filesystems == 0 &&
+                    !root_dir && !root_image &&
+                    !context->dynamic_user) {
+                        log_unit_debug(u, "Failed to set up namespace, assuming containerized execution and ignoring.");
+                        return 0;
+                }
+
+                return -EOPNOTSUPP;
         }
 
         return r;
@@ -5127,6 +5154,16 @@ static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
 
+static const char* const exec_directory_env_name_table[_EXEC_DIRECTORY_TYPE_MAX] = {
+        [EXEC_DIRECTORY_RUNTIME] = "RUNTIME_DIRECTORY",
+        [EXEC_DIRECTORY_STATE] = "STATE_DIRECTORY",
+        [EXEC_DIRECTORY_CACHE] = "CACHE_DIRECTORY",
+        [EXEC_DIRECTORY_LOGS] = "LOGS_DIRECTORY",
+        [EXEC_DIRECTORY_CONFIGURATION] = "CONFIGURATION_DIRECTORY",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(exec_directory_env_name, ExecDirectoryType);
+
 static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
         [EXEC_KEYRING_INHERIT] = "inherit",
         [EXEC_KEYRING_PRIVATE] = "private",
index 6c62cdf5954067ed3fc769866c8dcfbdd17ef7ec..6b17cc1d6f6da22014d720e601cfd9bf5b4f3539 100644 (file)
@@ -1384,15 +1384,8 @@ void job_add_to_gc_queue(Job *j) {
         j->in_gc_queue = true;
 }
 
-static int job_compare(const void *a, const void *b) {
-        Job *x = *(Job**) a, *y = *(Job**) b;
-
-        if (x->id < y->id)
-                return -1;
-        if (x->id > y->id)
-                return 1;
-
-        return 0;
+static int job_compare(Job * const *a, Job * const *b) {
+        return CMP((*a)->id, (*b)->id);
 }
 
 static size_t sort_job_list(Job **list, size_t n) {
@@ -1400,7 +1393,7 @@ static size_t sort_job_list(Job **list, size_t n) {
         size_t a, b;
 
         /* Order by numeric IDs */
-        qsort_safe(list, n, sizeof(Job*), job_compare);
+        typesafe_qsort(list, n, job_compare);
 
         /* Filter out duplicates */
         for (a = 0, b = 0; a < n; a++) {
index da05066cdd6ea48802606932cb22e7120366a5cb..5baa30d3dde69eac16c0c78918a887eaabc49933 100644 (file)
@@ -3788,7 +3788,7 @@ static int manager_run_environment_generators(Manager *m) {
         if (!generator_path_any(paths))
                 return 0;
 
-        return execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL);
+        return execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, m->environment);
 }
 
 static int manager_run_generators(Manager *m) {
@@ -3820,7 +3820,7 @@ static int manager_run_generators(Manager *m) {
 
         RUN_WITH_UMASK(0022)
                 execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC,
-                                    NULL, NULL, (char**) argv);
+                                    NULL, NULL, (char**) argv, m->environment);
 
 finish:
         lookup_paths_trim_generator(&m->lookup_paths);
index 7d12d6c330af6820326cacf733dcd75e00f872f0..c7cc1c755046ee0f4f1b7ca226256f307db87977 100644 (file)
@@ -397,22 +397,16 @@ static int append_protect_system(MountEntry **p, ProtectSystem protect_system, b
         }
 }
 
-static int mount_path_compare(const void *a, const void *b) {
-        const MountEntry *p = a, *q = b;
+static int mount_path_compare(const MountEntry *a, const MountEntry *b) {
         int d;
 
         /* If the paths are not equal, then order prefixes first */
-        d = path_compare(mount_entry_path(p), mount_entry_path(q));
+        d = path_compare(mount_entry_path(a), mount_entry_path(b));
         if (d != 0)
                 return d;
 
         /* If the paths are equal, check the mode */
-        if (p->mode < q->mode)
-                return -1;
-        if (p->mode > q->mode)
-                return 1;
-
-        return 0;
+        return CMP((int) a->mode, (int) b->mode);
 }
 
 static int prefix_where_needed(MountEntry *m, size_t n, const char *root_directory) {
@@ -632,7 +626,7 @@ add_symlink:
         t = strjoina("../", bn);
 
         if (symlink(t, sl) < 0)
-                log_debug_errno(errno, "Failed to symlink '%s' to '%s': %m", t, sl);
+                log_debug_errno(errno, "Failed to symlink '%s' to '%s', ignoring: %m", t, sl);
 
         return 0;
 }
@@ -657,35 +651,34 @@ static int mount_private_dev(MountEntry *m) {
         u = umask(0000);
 
         if (!mkdtemp(temporary_mount))
-                return -errno;
+                return log_debug_errno(errno, "Failed to create temporary directory '%s': %m", temporary_mount);
 
         dev = strjoina(temporary_mount, "/dev");
         (void) mkdir(dev, 0755);
         if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
-                r = -errno;
+                r = log_debug_errno(errno, "Failed to mount tmpfs on '%s': %m", dev);
                 goto fail;
         }
 
         devpts = strjoina(temporary_mount, "/dev/pts");
         (void) mkdir(devpts, 0755);
         if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
-                r = -errno;
+                r = log_debug_errno(errno, "Failed to bind mount /dev/pts on '%s': %m", devpts);
                 goto fail;
         }
 
-        /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx
-         * when /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible
-         * thus, in that case make a clone
-         *
-         * in nspawn and other containers it will be a symlink, in that case make it a symlink
-         */
+        /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx.
+         * When /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible.
+         * Thus, in that case make a clone.
+         * In nspawn and other containers it will be a symlink, in that case make it a symlink. */
         r = is_symlink("/dev/ptmx");
-        if (r < 0)
+        if (r < 0) {
+                log_debug_errno(r, "Failed to detect whether /dev/ptmx is a symlink or not: %m");
                 goto fail;
-        if (r > 0) {
+        } else if (r > 0) {
                 devptmx = strjoina(temporary_mount, "/dev/ptmx");
                 if (symlink("pts/ptmx", devptmx) < 0) {
-                        r = -errno;
+                        r = log_debug_errno(errno, "Failed to create a symlink '%s' to pts/ptmx: %m", devptmx);
                         goto fail;
                 }
         } else {
@@ -698,20 +691,23 @@ static int mount_private_dev(MountEntry *m) {
         (void) mkdir(devshm, 0755);
         r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
         if (r < 0) {
-                r = -errno;
+                r = log_debug_errno(errno, "Failed to bind mount /dev/shm on '%s': %m", devshm);
                 goto fail;
         }
 
         devmqueue = strjoina(temporary_mount, "/dev/mqueue");
         (void) mkdir(devmqueue, 0755);
-        (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
+        if (mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL) < 0)
+                log_debug_errno(errno, "Failed to bind mount /dev/mqueue on '%s', ignoring: %m", devmqueue);
 
         devhugepages = strjoina(temporary_mount, "/dev/hugepages");
         (void) mkdir(devhugepages, 0755);
-        (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
+        if (mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL) < 0)
+                log_debug_errno(errno, "Failed to bind mount /dev/hugepages on '%s', ignoring: %m", devhugepages);
 
         devlog = strjoina(temporary_mount, "/dev/log");
-        (void) symlink("/run/systemd/journal/dev-log", devlog);
+        if (symlink("/run/systemd/journal/dev-log", devlog) < 0)
+                log_debug_errno(errno, "Failed to create a symlink '%s' to /run/systemd/journal/dev-log, ignoring: %m", devlog);
 
         NULSTR_FOREACH(d, devnodes) {
                 r = clone_device_node(d, temporary_mount, &can_mknod);
@@ -720,7 +716,9 @@ static int mount_private_dev(MountEntry *m) {
                         goto fail;
         }
 
-        dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
+        r = dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
+        if (r < 0)
+                log_debug_errno(r, "Failed to setup basic device tree at '%s', ignoring: %m", temporary_mount);
 
         /* Create the /dev directory if missing. It is more likely to be
          * missing when the service is started with RootDirectory. This is
@@ -729,9 +727,12 @@ static int mount_private_dev(MountEntry *m) {
         (void) mkdir_p_label(mount_entry_path(m), 0755);
 
         /* Unmount everything in old /dev */
-        umount_recursive(mount_entry_path(m), 0);
+        r = umount_recursive(mount_entry_path(m), 0);
+        if (r < 0)
+                log_debug_errno(r, "Failed to unmount directories below '%s', ignoring: %m", mount_entry_path(m));
+
         if (mount(dev, mount_entry_path(m), NULL, MS_MOVE, NULL) < 0) {
-                r = -errno;
+                r = log_debug_errno(errno, "Failed to move mount point '%s' to '%s': %m", dev, mount_entry_path(m));
                 goto fail;
         }
 
@@ -1125,7 +1126,7 @@ static void normalize_mounts(const char *root_directory, MountEntry *mounts, siz
         assert(n_mounts);
         assert(mounts || *n_mounts == 0);
 
-        qsort_safe(mounts, *n_mounts, sizeof(MountEntry), mount_path_compare);
+        typesafe_qsort(mounts, *n_mounts, mount_path_compare);
 
         drop_duplicates(mounts, n_mounts);
         drop_outside_root(root_directory, mounts, n_mounts);
index 038345b7526b42efcb7f8ce4db3f679ed652c044..5bf332d9a9b9cea7a053b59fbdccd46d70127585 100644 (file)
@@ -435,7 +435,7 @@ int main(int argc, char *argv[]) {
         arguments[0] = NULL;
         arguments[1] = arg_verb;
         arguments[2] = NULL;
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
 
         if (can_initrd) {
                 r = switch_root_initramfs();
index 8775bc8a586d8d1c78e247e11e1c041c0f571a9a..aac80f3548eb304ff9aa06f8c8e345e7413dcaf6 100644 (file)
@@ -1313,7 +1313,7 @@ static int socket_symlink(Socket *s) {
         STRV_FOREACH(i, s->symlinks) {
                 (void) mkdir_parents_label(*i, s->directory_mode);
 
-                r = symlink_idempotent(p, *i);
+                r = symlink_idempotent(p, *i, false);
 
                 if (r == -EEXIST && s->remove_on_stop) {
                         /* If there's already something where we want to create the symlink, and the destructive
@@ -1321,7 +1321,7 @@ static int socket_symlink(Socket *s) {
                          * again. */
 
                         if (unlink(*i) >= 0)
-                                r = symlink_idempotent(p, *i);
+                                r = symlink_idempotent(p, *i, false);
                 }
 
                 if (r < 0)
index f1779e201eb41df848c6d198e0faf80eae1f8dd1..47313da231060f98e99727af8f03a4908f9d1a1a 100644 (file)
@@ -18,7 +18,7 @@
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "def.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fstab-util.h"
@@ -255,27 +255,27 @@ static int loopback_list_get(MountPoint **head) {
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
-                _cleanup_free_ MountPoint *lb = NULL;
+        FOREACH_DEVICE(e, d) {
+                _cleanup_free_ char *p = NULL;
                 const char *dn;
+                MountPoint *lb;
 
                 if (sd_device_get_devname(d, &dn) < 0)
                         continue;
 
-                lb = new0(MountPoint, 1);
+                p = strdup(dn);
+                if (!p)
+                        return -ENOMEM;
+
+                lb = new(MountPoint, 1);
                 if (!lb)
                         return -ENOMEM;
 
-                r = free_and_strdup(&lb->path, dn);
-                if (r < 0)
-                        return r;
+                *lb = (MountPoint) {
+                        .path = TAKE_PTR(p),
+                };
 
                 LIST_PREPEND(mount_point, *head, lb);
-                lb = NULL;
         }
 
         return 0;
@@ -304,32 +304,30 @@ static int dm_list_get(MountPoint **head) {
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
-                _cleanup_free_ MountPoint *m = NULL;
+        FOREACH_DEVICE(e, d) {
+                _cleanup_free_ char *p = NULL;
                 const char *dn;
+                MountPoint *m;
                 dev_t devnum;
 
-                if (sd_device_get_devnum(d, &devnum) < 0)
+                if (sd_device_get_devnum(d, &devnum) < 0 ||
+                    sd_device_get_devname(d, &dn) < 0)
                         continue;
 
-                if (sd_device_get_devname(d, &dn) < 0)
-                        continue;
+                p = strdup(dn);
+                if (!p)
+                        return -ENOMEM;
 
-                m = new0(MountPoint, 1);
+                m = new(MountPoint, 1);
                 if (!m)
                         return -ENOMEM;
 
-                m->devnum = devnum;
-                r = free_and_strdup(&m->path, dn);
-                if (r < 0)
-                        return r;
+                *m = (MountPoint) {
+                        .path = TAKE_PTR(p),
+                        .devnum = devnum,
+                };
 
                 LIST_PREPEND(mount_point, *head, m);
-                m = NULL;
         }
 
         return 0;
index a622db849b3714d2fdf4b1b3a97c3cbd85ad427c..b590d706767aa6099aa405547e1782f5be617f85 100644 (file)
@@ -271,7 +271,6 @@ static int parse_options(const char *options) {
 }
 
 static char* disk_description(const char *path) {
-
         static const char name_fields[] =
                 "ID_PART_ENTRY_NAME\0"
                 "DM_NAME\0"
@@ -279,9 +278,8 @@ static char* disk_description(const char *path) {
                 "ID_MODEL\0";
 
         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+        const char *i, *name;
         struct stat st;
-        const char *i;
-        int r;
 
         assert(path);
 
@@ -291,17 +289,13 @@ static char* disk_description(const char *path) {
         if (!S_ISBLK(st.st_mode))
                 return NULL;
 
-        r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
-        if (r < 0)
+        if (sd_device_new_from_devnum(&device, 'b', st.st_rdev) < 0)
                 return NULL;
 
-        NULSTR_FOREACH(i, name_fields) {
-                const char *name;
-
-                r = sd_device_get_property_value(device, i, &name);
-                if (r >= 0 && !isempty(name))
+        NULSTR_FOREACH(i, name_fields)
+                if (sd_device_get_property_value(device, i, &name) >= 0 &&
+                    !isempty(name))
                         return strdup(name);
-        }
 
         return NULL;
 }
index 50f838a421127c83773e73861ea2f0a4c5ca61a0..132714fdddb78ef81cc3dfe9ecab216d00d72d95 100644 (file)
@@ -357,8 +357,7 @@ int main(int argc, char *argv[]) {
                 root_directory = true;
         }
 
-        r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type);
-        if (r >= 0) {
+        if (sd_device_get_property_value(dev, "ID_FS_TYPE", &type) >= 0) {
                 r = fsck_exists(type);
                 if (r < 0)
                         log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device);
index d549dc95ffe5608ffc1d5f28dfb6e55891d6f3f3..caf7a27ef135af547345697ea67235e54cc6156f 100644 (file)
@@ -4,6 +4,7 @@
 #include "log.h"
 #include "fileio.h"
 #include "fuzz.h"
+#include "tests.h"
 
 /* This is a test driver for the systemd fuzzers that provides main function
  * for regression testing outside of oss-fuzz (https://github.com/google/oss-fuzz)
@@ -16,9 +17,7 @@ int main(int argc, char **argv) {
         size_t size;
         char *name;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         for (i = 1; i < argc; i++) {
                 _cleanup_free_ char *buf = NULL;
index a088df811fd49dda7362165a2eca6199cf196f67..6b752214265107b21e6566e154378d6dc9f3c547 100644 (file)
@@ -462,34 +462,34 @@ static int open_parent(dev_t devnum, int *ret) {
                 r = sd_device_get_syspath(d, &name);
                 if (r < 0) {
                         log_debug_errno(r, "Device %u:%u does not have a name, ignoring: %m", major(devnum), minor(devnum));
-                        goto not_found;
+                        return 0;
                 }
         }
 
         r = sd_device_get_parent(d, &parent);
         if (r < 0) {
                 log_debug_errno(r, "%s: not a partitioned device, ignoring: %m", name);
-                goto not_found;
+                return 0;
         }
 
         /* Does it have a devtype? */
         r = sd_device_get_devtype(parent, &devtype);
         if (r < 0) {
                 log_debug_errno(r, "%s: parent doesn't have a device type, ignoring: %m", name);
-                goto not_found;
+                return 0;
         }
 
         /* Is this a disk or a partition? We only care for disks... */
         if (!streq(devtype, "disk")) {
                 log_debug("%s: parent isn't a raw disk, ignoring.", name);
-                goto not_found;
+                return 0;
         }
 
         /* Does it have a device node? */
         r = sd_device_get_devname(parent, &node);
         if (r < 0) {
                 log_debug_errno(r, "%s: parent device does not have device node, ignoring: %m", name);
-                goto not_found;
+                return 0;
         }
 
         log_debug("%s: root device %s.", name, node);
@@ -497,7 +497,7 @@ static int open_parent(dev_t devnum, int *ret) {
         r = sd_device_get_devnum(parent, &pn);
         if (r < 0) {
                 log_debug_errno(r, "%s: parent device is not a proper block device, ignoring: %m", name);
-                goto not_found;
+                return 0;
         }
 
         fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -506,14 +506,9 @@ static int open_parent(dev_t devnum, int *ret) {
 
         *ret = fd;
         return 1;
-
-not_found:
-        *ret = -1;
-        return 0;
 }
 
 static int enumerate_partitions(dev_t devnum) {
-
         _cleanup_close_ int fd = -1;
         _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
         int r, k;
index 8a99510619e2d955c88c27818b9156656c03baa5..be64a26d64ff70258bf783eac2ffe0829ee903ba 100644 (file)
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <ctype.h>
 #include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
+
+#include "sd-hwdb.h"
 
 #include "alloc-util.h"
-#include "conf-files.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hwdb-internal.h"
 #include "hwdb-util.h"
-#include "label.h"
-#include "mkdir.h"
-#include "path-util.h"
 #include "selinux-util.h"
-#include "strbuf.h"
-#include "string-util.h"
-#include "strv.h"
 #include "terminal-util.h"
 #include "util.h"
 #include "verbs.h"
 
-/*
- * Generic udev properties, key-value database based on modalias strings.
- * Uses a Patricia/radix trie to index all matches for efficient lookup.
- */
-
-static const char *arg_hwdb_bin_dir = "/etc/udev";
-static const char *arg_root = "";
-static bool arg_strict;
-
-static const char * const conf_file_dirs[] = {
-        "/etc/udev/hwdb.d",
-        UDEVLIBEXECDIR "/hwdb.d",
-        NULL
-};
-
-/* in-memory trie objects */
-struct trie {
-        struct trie_node *root;
-        struct strbuf *strings;
-
-        size_t nodes_count;
-        size_t children_count;
-        size_t values_count;
-};
-
-struct trie_node {
-        /* prefix, common part for all children of this node */
-        size_t prefix_off;
-
-        /* sorted array of pointers to children nodes */
-        struct trie_child_entry *children;
-        uint8_t children_count;
-
-        /* sorted array of key-value pairs */
-        struct trie_value_entry *values;
-        size_t values_count;
-};
-
-/* children array item with char (0-255) index */
-struct trie_child_entry {
-        uint8_t c;
-        struct trie_node *child;
-};
-
-/* value array item with key-value pairs */
-struct trie_value_entry {
-        size_t key_off;
-        size_t value_off;
-        size_t filename_off;
-        uint32_t line_number;
-        uint16_t file_priority;
-};
-
-static int trie_children_cmp(const void *v1, const void *v2) {
-        const struct trie_child_entry *n1 = v1;
-        const struct trie_child_entry *n2 = v2;
-
-        return n1->c - n2->c;
-}
-
-static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
-        struct trie_child_entry *child;
-
-        /* extend array, add new entry, sort for bisection */
-        child = reallocarray(node->children, node->children_count + 1, sizeof(struct trie_child_entry));
-        if (!child)
-                return -ENOMEM;
-
-        node->children = child;
-        trie->children_count++;
-        node->children[node->children_count].c = c;
-        node->children[node->children_count].child = node_child;
-        node->children_count++;
-        qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
-        trie->nodes_count++;
-
-        return 0;
-}
-
-static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
-        struct trie_child_entry *child;
-        struct trie_child_entry search;
-
-        search.c = c;
-        child = bsearch_safe(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
-        if (child)
-                return child->child;
-        return NULL;
-}
-
-static void trie_node_cleanup(struct trie_node *node) {
-        size_t i;
-
-        for (i = 0; i < node->children_count; i++)
-                trie_node_cleanup(node->children[i].child);
-        free(node->children);
-        free(node->values);
-        free(node);
-}
-
-static void trie_free(struct trie *trie) {
-        if (!trie)
-                return;
-
-        if (trie->root)
-                trie_node_cleanup(trie->root);
-
-        strbuf_cleanup(trie->strings);
-        free(trie);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free);
-
-static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
-        const struct trie_value_entry *val1 = v1;
-        const struct trie_value_entry *val2 = v2;
-        struct trie *trie = arg;
-
-        return strcmp(trie->strings->buf + val1->key_off,
-                      trie->strings->buf + val2->key_off);
-}
-
-static int trie_node_add_value(struct trie *trie, struct trie_node *node,
-                               const char *key, const char *value,
-                               const char *filename, uint16_t file_priority, uint32_t line_number) {
-        ssize_t k, v, fn;
-        struct trie_value_entry *val;
-
-        k = strbuf_add_string(trie->strings, key, strlen(key));
-        if (k < 0)
-                return k;
-        v = strbuf_add_string(trie->strings, value, strlen(value));
-        if (v < 0)
-                return v;
-        fn = strbuf_add_string(trie->strings, filename, strlen(filename));
-        if (fn < 0)
-                return fn;
-
-        if (node->values_count) {
-                struct trie_value_entry search = {
-                        .key_off = k,
-                        .value_off = v,
-                };
-
-                val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
-                if (val) {
-                        /* At this point we have 2 identical properties on the same match-string.
-                         * Since we process files in order, we just replace the previous value.
-                         */
-                        val->value_off = v;
-                        val->filename_off = fn;
-                        val->file_priority = file_priority;
-                        val->line_number = line_number;
-                        return 0;
-                }
-        }
-
-        /* extend array, add new entry, sort for bisection */
-        val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry));
-        if (!val)
-                return -ENOMEM;
-        trie->values_count++;
-        node->values = val;
-        node->values[node->values_count].key_off = k;
-        node->values[node->values_count].value_off = v;
-        node->values[node->values_count].filename_off = fn;
-        node->values[node->values_count].file_priority = file_priority;
-        node->values[node->values_count].line_number = line_number;
-        node->values_count++;
-        qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
-        return 0;
-}
-
-static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
-                       const char *key, const char *value,
-                       const char *filename, uint16_t file_priority, uint32_t line_number) {
-        size_t i = 0;
-        int r = 0;
-
-        for (;;) {
-                size_t p;
-                uint8_t c;
-                struct trie_node *child;
-
-                for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
-                        _cleanup_free_ char *s = NULL;
-                        ssize_t off;
-                        _cleanup_free_ struct trie_node *new_child = NULL;
-
-                        if (c == search[i + p])
-                                continue;
-
-                        /* split node */
-                        new_child = new0(struct trie_node, 1);
-                        if (!new_child)
-                                return -ENOMEM;
-
-                        /* move values from parent to child */
-                        new_child->prefix_off = node->prefix_off + p+1;
-                        new_child->children = node->children;
-                        new_child->children_count = node->children_count;
-                        new_child->values = node->values;
-                        new_child->values_count = node->values_count;
-
-                        /* update parent; use strdup() because the source gets realloc()d */
-                        s = strndup(trie->strings->buf + node->prefix_off, p);
-                        if (!s)
-                                return -ENOMEM;
-
-                        off = strbuf_add_string(trie->strings, s, p);
-                        if (off < 0)
-                                return off;
-
-                        node->prefix_off = off;
-                        node->children = NULL;
-                        node->children_count = 0;
-                        node->values = NULL;
-                        node->values_count = 0;
-                        r = node_add_child(trie, node, new_child, c);
-                        if (r < 0)
-                                return r;
-
-                        new_child = NULL; /* avoid cleanup */
-                        break;
-                }
-                i += p;
-
-                c = search[i];
-                if (c == '\0')
-                        return trie_node_add_value(trie, node, key, value, filename, file_priority, line_number);
-
-                child = node_lookup(node, c);
-                if (!child) {
-                        ssize_t off;
-
-                        /* new child */
-                        child = new0(struct trie_node, 1);
-                        if (!child)
-                                return -ENOMEM;
-
-                        off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
-                        if (off < 0) {
-                                free(child);
-                                return off;
-                        }
-
-                        child->prefix_off = off;
-                        r = node_add_child(trie, node, child, c);
-                        if (r < 0) {
-                                free(child);
-                                return r;
-                        }
-
-                        return trie_node_add_value(trie, child, key, value, filename, file_priority, line_number);
-                }
-
-                node = child;
-                i++;
-        }
-}
-
-struct trie_f {
-        FILE *f;
-        struct trie *trie;
-        uint64_t strings_off;
-
-        uint64_t nodes_count;
-        uint64_t children_count;
-        uint64_t values_count;
-};
-
-/* calculate the storage space for the nodes, children arrays, value arrays */
-static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
-        uint64_t i;
-
-        for (i = 0; i < node->children_count; i++)
-                trie_store_nodes_size(trie, node->children[i].child);
-
-        trie->strings_off += sizeof(struct trie_node_f);
-        for (i = 0; i < node->children_count; i++)
-                trie->strings_off += sizeof(struct trie_child_entry_f);
-        for (i = 0; i < node->values_count; i++)
-                trie->strings_off += sizeof(struct trie_value_entry2_f);
-}
-
-static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
-        uint64_t i;
-        struct trie_node_f n = {
-                .prefix_off = htole64(trie->strings_off + node->prefix_off),
-                .children_count = node->children_count,
-                .values_count = htole64(node->values_count),
-        };
-        _cleanup_free_ struct trie_child_entry_f *children = NULL;
-        int64_t node_off;
-
-        if (node->children_count) {
-                children = new(struct trie_child_entry_f, node->children_count);
-                if (!children)
-                        return -ENOMEM;
-        }
-
-        /* post-order recursion */
-        for (i = 0; i < node->children_count; i++) {
-                int64_t child_off;
-
-                child_off = trie_store_nodes(trie, node->children[i].child);
-                if (child_off < 0)
-                        return child_off;
-
-                children[i] = (struct trie_child_entry_f) {
-                        .c = node->children[i].c,
-                        .child_off = htole64(child_off),
-                };
-        }
-
-        /* write node */
-        node_off = ftello(trie->f);
-        fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
-        trie->nodes_count++;
-
-        /* append children array */
-        if (node->children_count) {
-                fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
-                trie->children_count += node->children_count;
-        }
-
-        /* append values array */
-        for (i = 0; i < node->values_count; i++) {
-                struct trie_value_entry2_f v = {
-                        .key_off = htole64(trie->strings_off + node->values[i].key_off),
-                        .value_off = htole64(trie->strings_off + node->values[i].value_off),
-                        .filename_off = htole64(trie->strings_off + node->values[i].filename_off),
-                        .line_number = htole32(node->values[i].line_number),
-                        .file_priority = htole16(node->values[i].file_priority),
-                };
-
-                fwrite(&v, sizeof(struct trie_value_entry2_f), 1, trie->f);
-        }
-        trie->values_count += node->values_count;
+static const char *arg_hwdb_bin_dir = NULL;
+static const char *arg_root = NULL;
+static bool arg_strict = false;
 
-        return node_off;
+static int verb_query(int argc, char *argv[], void *userdata) {
+        return hwdb_query(argv[1]);
 }
 
-static int trie_store(struct trie *trie, const char *filename) {
-        struct trie_f t = {
-                .trie = trie,
-        };
-        _cleanup_free_ char *filename_tmp = NULL;
-        int64_t pos;
-        int64_t root_off;
-        int64_t size;
-        struct trie_header_f h = {
-                .signature = HWDB_SIG,
-                .tool_version = htole64(atoi(PACKAGE_VERSION)),
-                .header_size = htole64(sizeof(struct trie_header_f)),
-                .node_size = htole64(sizeof(struct trie_node_f)),
-                .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
-                .value_entry_size = htole64(sizeof(struct trie_value_entry2_f)),
-        };
-        int r;
-
-        /* calculate size of header, nodes, children entries, value entries */
-        t.strings_off = sizeof(struct trie_header_f);
-        trie_store_nodes_size(&t, trie->root);
-
-        r = fopen_temporary(filename, &t.f, &filename_tmp);
-        if (r < 0)
-                return r;
-        fchmod(fileno(t.f), 0444);
-
-        /* write nodes */
-        if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
-                goto error_fclose;
-
-        root_off = trie_store_nodes(&t, trie->root);
-        h.nodes_root_off = htole64(root_off);
-        pos = ftello(t.f);
-        h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
-
-        /* write string buffer */
-        fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
-        h.strings_len = htole64(trie->strings->len);
-
-        /* write header */
-        size = ftello(t.f);
-        h.file_size = htole64(size);
-        if (fseeko(t.f, 0, SEEK_SET) < 0)
-                goto error_fclose;
-        fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
-
-        if (ferror(t.f))
-                goto error_fclose;
-        if (fflush(t.f) < 0)
-                goto error_fclose;
-        if (fsync(fileno(t.f)) < 0)
-                goto error_fclose;
-        if (rename(filename_tmp, filename) < 0)
-                goto error_fclose;
-
-        /* write succeeded */
-        fclose(t.f);
-
-        log_debug("=== trie on-disk ===");
-        log_debug("size:             %8"PRIi64" bytes", size);
-        log_debug("header:           %8zu bytes", sizeof(struct trie_header_f));
-        log_debug("nodes:            %8"PRIu64" bytes (%8"PRIu64")",
-                  t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
-        log_debug("child pointers:   %8"PRIu64" bytes (%8"PRIu64")",
-                  t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
-        log_debug("value pointers:   %8"PRIu64" bytes (%8"PRIu64")",
-                  t.values_count * sizeof(struct trie_value_entry2_f), t.values_count);
-        log_debug("string store:     %8zu bytes", trie->strings->len);
-        log_debug("strings start:    %8"PRIu64, t.strings_off);
-        return 0;
-
- error_fclose:
-        r = -errno;
-        fclose(t.f);
-        unlink(filename_tmp);
-        return r;
-}
-
-static int insert_data(struct trie *trie, char **match_list, char *line,
-                       const char *filename, uint16_t file_priority, uint32_t line_number) {
-        char *value, **entry;
-
-        assert(line[0] == ' ');
-
-        value = strchr(line, '=');
-        if (!value)
-                return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
-                                  "Key-value pair expected but got \"%s\", ignoring", line);
-
-        value[0] = '\0';
-        value++;
-
-        /* Replace multiple leading spaces by a single space */
-        while (isblank(line[0]) && isblank(line[1]))
-                line++;
-
-        if (isempty(line + 1) || isempty(value))
-                return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
-                                  "Empty %s in \"%s=%s\", ignoring",
-                                  isempty(line + 1) ? "key" : "value",
-                                  line, value);
-
-        STRV_FOREACH(entry, match_list)
-                trie_insert(trie, trie->root, *entry, line, value, filename, file_priority, line_number);
-
-        return 0;
-}
-
-static int import_file(struct trie *trie, const char *filename, uint16_t file_priority) {
-        enum {
-                HW_NONE,
-                HW_MATCH,
-                HW_DATA,
-        } state = HW_NONE;
-        _cleanup_fclose_ FILE *f = NULL;
-        char line[LINE_MAX];
-        _cleanup_strv_free_ char **match_list = NULL;
-        uint32_t line_number = 0;
-        char *match = NULL;
-        int r = 0, err;
-
-        f = fopen(filename, "re");
-        if (!f)
-                return -errno;
-
-        while (fgets(line, sizeof(line), f)) {
-                size_t len;
-                char *pos;
-
-                ++line_number;
-
-                /* comment line */
-                if (line[0] == '#')
-                        continue;
-
-                /* strip trailing comment */
-                pos = strchr(line, '#');
-                if (pos)
-                        pos[0] = '\0';
-
-                /* strip trailing whitespace */
-                len = strlen(line);
-                while (len > 0 && isspace(line[len-1]))
-                        len--;
-                line[len] = '\0';
-
-                switch (state) {
-                case HW_NONE:
-                        if (len == 0)
-                                break;
-
-                        if (line[0] == ' ') {
-                                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
-                                           "Match expected but got indented property \"%s\", ignoring line", line);
-                                r = -EINVAL;
-                                break;
-                        }
-
-                        /* start of record, first match */
-                        state = HW_MATCH;
-
-                        match = strdup(line);
-                        if (!match)
-                                return -ENOMEM;
-
-                        err = strv_consume(&match_list, match);
-                        if (err < 0)
-                                return err;
-
-                        break;
-
-                case HW_MATCH:
-                        if (len == 0) {
-                                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
-                                           "Property expected, ignoring record with no properties");
-                                r = -EINVAL;
-                                state = HW_NONE;
-                                strv_clear(match_list);
-                                break;
-                        }
-
-                        if (line[0] != ' ') {
-                                /* another match */
-                                match = strdup(line);
-                                if (!match)
-                                        return -ENOMEM;
-
-                                err = strv_consume(&match_list, match);
-                                if (err < 0)
-                                        return err;
-
-                                break;
-                        }
-
-                        /* first data */
-                        state = HW_DATA;
-                        err = insert_data(trie, match_list, line, filename, file_priority, line_number);
-                        if (err < 0)
-                                r = err;
-                        break;
-
-                case HW_DATA:
-                        if (len == 0) {
-                                /* end of record */
-                                state = HW_NONE;
-                                strv_clear(match_list);
-                                break;
-                        }
-
-                        if (line[0] != ' ') {
-                                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
-                                           "Property or empty line expected, got \"%s\", ignoring record", line);
-                                r = -EINVAL;
-                                state = HW_NONE;
-                                strv_clear(match_list);
-                                break;
-                        }
-
-                        err = insert_data(trie, match_list, line, filename, file_priority, line_number);
-                        if (err < 0)
-                                r = err;
-                        break;
-                };
-        }
-
-        if (state == HW_MATCH)
-                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
-                           "Property expected, ignoring record with no properties");
-
-        return r;
-}
-
-static int hwdb_query(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
-        const char *key, *value;
-        const char *modalias;
-        int r;
-
-        assert(argc >= 2);
-        assert(argv);
-
-        modalias = argv[1];
-
-        r = sd_hwdb_new(&hwdb);
-        if (r < 0)
-                return r;
-
-        SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value)
-                printf("%s=%s\n", key, value);
-
-        return 0;
-}
-
-static int hwdb_update(int argc, char *argv[], void *userdata) {
-        _cleanup_free_ char *hwdb_bin = NULL;
-        _cleanup_(trie_freep) struct trie *trie = NULL;
-        _cleanup_strv_free_ char **files = NULL;
-        char **f;
-        uint16_t file_priority = 1;
-        int r = 0, err;
-
-        trie = new0(struct trie, 1);
-        if (!trie)
-                return -ENOMEM;
-
-        /* string store */
-        trie->strings = strbuf_new();
-        if (!trie->strings)
-                return -ENOMEM;
-
-        /* index */
-        trie->root = new0(struct trie_node, 1);
-        if (!trie->root)
-                return -ENOMEM;
-
-        trie->nodes_count++;
-
-        err = conf_files_list_strv(&files, ".hwdb", arg_root, 0, conf_file_dirs);
-        if (err < 0)
-                return log_error_errno(err, "Failed to enumerate hwdb files: %m");
-
-        STRV_FOREACH(f, files) {
-                log_debug("Reading file \"%s\"", *f);
-                err = import_file(trie, *f, file_priority++);
-                if (err < 0 && arg_strict)
-                        r = err;
-        }
-
-        strbuf_complete(trie->strings);
-
-        log_debug("=== trie in-memory ===");
-        log_debug("nodes:            %8zu bytes (%8zu)",
-                  trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
-        log_debug("children arrays:  %8zu bytes (%8zu)",
-                  trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
-        log_debug("values arrays:    %8zu bytes (%8zu)",
-                  trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
-        log_debug("strings:          %8zu bytes",
-                  trie->strings->len);
-        log_debug("strings incoming: %8zu bytes (%8zu)",
-                  trie->strings->in_len, trie->strings->in_count);
-        log_debug("strings dedup'ed: %8zu bytes (%8zu)",
-                  trie->strings->dedup_len, trie->strings->dedup_count);
-
-        hwdb_bin = path_join(arg_root, arg_hwdb_bin_dir, "hwdb.bin");
-        if (!hwdb_bin)
-                return -ENOMEM;
-
-        mkdir_parents_label(hwdb_bin, 0755);
-        err = trie_store(trie, hwdb_bin);
-        if (err < 0)
-                return log_error_errno(err, "Failure writing database %s: %m", hwdb_bin);
-
-        err = label_fix(hwdb_bin, 0);
-        if (err < 0)
-                return err;
-
-        return r;
+static int verb_update(int argc, char *argv[], void *userdata) {
+        return hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, false);
 }
 
 static int help(void) {
@@ -733,7 +69,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0)
                 switch(c) {
 
                 case 'h':
@@ -760,15 +96,14 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unknown option");
                 }
-        }
 
         return 1;
 }
 
 static int hwdb_main(int argc, char *argv[]) {
         static const Verb verbs[] = {
-                { "update", 1, 1, 0, hwdb_update },
-                { "query",  2, 2, 0, hwdb_query  },
+                { "update", 1, 1, 0, verb_update },
+                { "query",  2, 2, 0, verb_query  },
                 {},
         };
 
index 1cf29e26f16ca570910dd1dcbd5e521402c367f7..3fbd0677906c5b572b8303eb7181706614d8a9ea 100644 (file)
@@ -14,11 +14,13 @@ void import_compress_free(ImportCompress *c) {
                         deflateEnd(&c->gzip);
                 else
                         inflateEnd(&c->gzip);
+#if HAVE_BZIP2
         } else if (c->type == IMPORT_COMPRESS_BZIP2) {
                 if (c->encoding)
                         BZ2_bzCompressEnd(&c->bzip2);
                 else
                         BZ2_bzDecompressEnd(&c->bzip2);
+#endif
         }
 
         c->type = IMPORT_COMPRESS_UNKNOWN;
@@ -65,12 +67,14 @@ int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
 
                 c->type = IMPORT_COMPRESS_GZIP;
 
+#if HAVE_BZIP2
         } else if (memcmp(data, bzip2_signature, sizeof(bzip2_signature)) == 0) {
                 r = BZ2_bzDecompressInit(&c->bzip2, 0, 0);
                 if (r != BZ_OK)
                         return -EIO;
 
                 c->type = IMPORT_COMPRESS_BZIP2;
+#endif
         } else
                 c->type = IMPORT_COMPRESS_UNCOMPRESSED;
 
@@ -149,6 +153,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
 
                 break;
 
+#if HAVE_BZIP2
         case IMPORT_COMPRESS_BZIP2:
                 c->bzip2.next_in = (void*) data;
                 c->bzip2.avail_in = size;
@@ -169,6 +174,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
                 }
 
                 break;
+#endif
 
         default:
                 assert_not_reached("Unknown compression");
@@ -203,6 +209,7 @@ int import_compress_init(ImportCompress *c, ImportCompressType t) {
                 c->type = IMPORT_COMPRESS_GZIP;
                 break;
 
+#if HAVE_BZIP2
         case IMPORT_COMPRESS_BZIP2:
                 r = BZ2_bzCompressInit(&c->bzip2, 9, 0, 0);
                 if (r != BZ_OK)
@@ -210,6 +217,7 @@ int import_compress_init(ImportCompress *c, ImportCompressType t) {
 
                 c->type = IMPORT_COMPRESS_BZIP2;
                 break;
+#endif
 
         case IMPORT_COMPRESS_UNCOMPRESSED:
                 c->type = IMPORT_COMPRESS_UNCOMPRESSED;
@@ -307,6 +315,7 @@ int import_compress(ImportCompress *c, const void *data, size_t size, void **buf
 
                 break;
 
+#if HAVE_BZIP2
         case IMPORT_COMPRESS_BZIP2:
 
                 c->bzip2.next_in = (void*) data;
@@ -328,6 +337,7 @@ int import_compress(ImportCompress *c, const void *data, size_t size, void **buf
                 }
 
                 break;
+#endif
 
         case IMPORT_COMPRESS_UNCOMPRESSED:
 
@@ -411,6 +421,7 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size
 
                 break;
 
+#if HAVE_BZIP2
         case IMPORT_COMPRESS_BZIP2:
                 c->bzip2.avail_in = 0;
 
@@ -430,6 +441,7 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size
                 } while (r != BZ_STREAM_END);
 
                 break;
+#endif
 
         case IMPORT_COMPRESS_UNCOMPRESSED:
                 break;
@@ -446,7 +458,9 @@ static const char* const import_compress_type_table[_IMPORT_COMPRESS_TYPE_MAX] =
         [IMPORT_COMPRESS_UNCOMPRESSED] = "uncompressed",
         [IMPORT_COMPRESS_XZ] = "xz",
         [IMPORT_COMPRESS_GZIP] = "gzip",
+#if HAVE_BZIP2
         [IMPORT_COMPRESS_BZIP2] = "bzip2",
+#endif
 };
 
 DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);
index 6fb87ccdfb6a7137b12eff02f971e5280df99983..859bd0e1a47fddf05b5f7622310e721a4ffd883d 100644 (file)
@@ -1,7 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#if HAVE_BZIP2
 #include <bzlib.h>
+#endif
 #include <lzma.h>
 #include <sys/types.h>
 #include <zlib.h>
@@ -24,7 +26,9 @@ typedef struct ImportCompress {
         union {
                 lzma_stream xz;
                 z_stream gzip;
+#if HAVE_BZIP2
                 bz_stream bzip2;
+#endif
         };
 } ImportCompress;
 
index 4ae1136e8604a3d4d4be6325d2413837a81fc200..c59bf52d7466ccd9b737cc8f6d0c024486105cc6 100644 (file)
@@ -56,23 +56,22 @@ static void catalog_hash_func(const void *p, struct siphash *state) {
         siphash24_compress(i->language, strlen(i->language), state);
 }
 
-static int catalog_compare_func(const void *a, const void *b) {
-        const CatalogItem *i = a, *j = b;
+static int catalog_compare_func(const CatalogItem *a, const CatalogItem *b) {
         unsigned k;
         int r;
 
-        for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
-                r = CMP(i->id.bytes[k], j->id.bytes[k]);
+        for (k = 0; k < ELEMENTSOF(b->id.bytes); k++) {
+                r = CMP(a->id.bytes[k], b->id.bytes[k]);
                 if (r != 0)
                         return r;
         }
 
-        return strcmp(i->language, j->language);
+        return strcmp(a->language, b->language);
 }
 
 const struct hash_ops catalog_hash_ops = {
         .hash = catalog_hash_func,
-        .compare = catalog_compare_func
+        .compare = (comparison_fn_t) catalog_compare_func,
 };
 
 static bool next_header(const char **s) {
@@ -495,7 +494,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
         }
 
         assert(n == hashmap_size(h));
-        qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
+        typesafe_qsort(items, n, catalog_compare_func);
 
         strbuf_complete(sb);
 
@@ -567,21 +566,21 @@ static const char *find_id(void *p, sd_id128_t id) {
                 strncpy(key.language, loc, sizeof(key.language));
                 key.language[strcspn(key.language, ".@")] = 0;
 
-                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func);
                 if (!f) {
                         char *e;
 
                         e = strchr(key.language, '_');
                         if (e) {
                                 *e = 0;
-                                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+                                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func);
                         }
                 }
         }
 
         if (!f) {
                 zero(key.language);
-                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func);
         }
 
         if (!f)
index 62e7f68a13762891f963774f9b39b723c2e8af00..ee6e25e5e82fccf0b217dde1ca10ee9bed2cc54e 100644 (file)
@@ -1933,14 +1933,8 @@ int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t)
         return r;
 }
 
-static int entry_item_cmp(const void *_a, const void *_b) {
-        const EntryItem *a = _a, *b = _b;
-
-        if (le64toh(a->object_offset) < le64toh(b->object_offset))
-                return -1;
-        if (le64toh(a->object_offset) > le64toh(b->object_offset))
-                return 1;
-        return 0;
+static int entry_item_cmp(const EntryItem *a, const EntryItem *b) {
+        return CMP(le64toh(a->object_offset), le64toh(b->object_offset));
 }
 
 int journal_file_append_entry(
@@ -1999,7 +1993,7 @@ int journal_file_append_entry(
 
         /* Order by the position on disk, in order to improve seek
          * times for rotating media. */
-        qsort_safe(items, n_iovec, sizeof(EntryItem), entry_item_cmp);
+        typesafe_qsort(items, n_iovec, entry_item_cmp);
 
         r = journal_file_append_entry_internal(f, ts, boot_id, xor_hash, items, n_iovec, seqnum, ret, offset);
 
index 8d3ae71440d6d804221b63e01a37da0ec48c29f3..840fb69ee0202a0ff557af0c8677dbd5784a3c8c 100644 (file)
@@ -29,30 +29,21 @@ struct vacuum_info {
         bool have_seqnum;
 };
 
-static int vacuum_compare(const void *_a, const void *_b) {
-        const struct vacuum_info *a, *b;
-
-        a = _a;
-        b = _b;
+static int vacuum_compare(const struct vacuum_info *a, const struct vacuum_info *b) {
+        int r;
 
         if (a->have_seqnum && b->have_seqnum &&
-            sd_id128_equal(a->seqnum_id, b->seqnum_id)) {
-                if (a->seqnum < b->seqnum)
-                        return -1;
-                else if (a->seqnum > b->seqnum)
-                        return 1;
-                else
-                        return 0;
-        }
+            sd_id128_equal(a->seqnum_id, b->seqnum_id))
+                return CMP(a->seqnum, b->seqnum);
 
-        if (a->realtime < b->realtime)
-                return -1;
-        else if (a->realtime > b->realtime)
-                return 1;
-        else if (a->have_seqnum && b->have_seqnum)
+        r = CMP(a->realtime, b->realtime);
+        if (r != 0)
+                return r;
+
+        if (a->have_seqnum && b->have_seqnum)
                 return memcmp(&a->seqnum_id, &b->seqnum_id, 16);
-        else
-                return strcmp(a->filename, b->filename);
+
+        return strcmp(a->filename, b->filename);
 }
 
 static void patch_realtime(
@@ -292,7 +283,7 @@ int journal_directory_vacuum(
                 sum += size;
         }
 
-        qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
+        typesafe_qsort(list, n_list, vacuum_compare);
 
         for (i = 0; i < n_list; i++) {
                 unsigned left;
index d9ee557b9c4a036b8f13190605d4cd06871d5e1d..e9a751bdfd75ddd307f13ed3d6f4e32b822ce396 100644 (file)
@@ -201,14 +201,12 @@ static void test_catalog_file_lang(void) {
 
 int main(int argc, char *argv[]) {
         _cleanup_(unlink_tempfilep) char database[] = "/tmp/test-catalog.XXXXXX";
-        _cleanup_free_ char *text = NULL, *catalog_dir = NULL;
+        _cleanup_free_ char *text = NULL;
         int r;
 
         setlocale(LC_ALL, "de_DE.UTF-8");
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         /* If test-catalog is located at the build directory, then use catalogs in that.
          * If it is not, e.g. installed by systemd-tests package, then use installed catalogs. */
index 411df3fa7ab7b5543c9c68eef35669bb14927f43..7f13b611e6ad5d41b0a8a7984c67bc7cab327657 100644 (file)
@@ -8,6 +8,7 @@
 #include "process-util.h"
 #include "random-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 typedef int (compress_t)(const void *src, uint64_t src_size, void *dst,
@@ -142,30 +143,23 @@ static void test_compress_decompress(const char* label, const char* type,
 
 int main(int argc, char *argv[]) {
 #if HAVE_XZ || HAVE_LZ4
-        const char *i;
-        int r;
-
-        log_set_max_level(LOG_INFO);
+        test_setup_logging(LOG_INFO);
 
         if (argc >= 2) {
                 unsigned x;
 
                 assert_se(safe_atou(argv[1], &x) >= 0);
                 arg_duration = x * USEC_PER_SEC;
-        } else {
-                bool slow;
-
-                r = getenv_bool("SYSTEMD_SLOW_TESTS");
-                slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
-
-                arg_duration = slow ? 2 * USEC_PER_SEC : USEC_PER_SEC / 50;
-        }
+        } else
+                arg_duration = slow_tests_enabled() ?
+                        2 * USEC_PER_SEC : USEC_PER_SEC / 50;
 
         if (argc == 3)
                 (void) safe_atozu(argv[2], &arg_start);
         else
                 arg_start = getpid_cached();
 
+        const char *i;
         NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
 #if HAVE_XZ
                 test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
@@ -176,6 +170,6 @@ int main(int argc, char *argv[]) {
         }
         return 0;
 #else
-        return EXIT_TEST_SKIP;
+        return log_tests_skipped("No compression feature is enabled");
 #endif
 }
index 791c6fdffb1bfdb0af3cd7a7e8806657eecbb016..7addf318d69544fe84a207868ebfa762ae3d25b2 100644 (file)
@@ -12,6 +12,7 @@
 #include "macro.h"
 #include "path-util.h"
 #include "random-util.h"
+#include "tests.h"
 #include "util.h"
 
 #if HAVE_XZ
@@ -253,7 +254,7 @@ int main(int argc, char *argv[]) {
         memcpy(huge, "HUGE=", 5);
         char_array_0(huge);
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         random_bytes(data + 7, sizeof(data) - 7);
 
@@ -305,6 +306,7 @@ int main(int argc, char *argv[]) {
 
         return 0;
 #else
+        log_info("/* XZ and LZ4 tests skipped */");
         return EXIT_TEST_SKIP;
 #endif
 }
index b25a983498cd0b07ea5ca5fb8b2f0656a8bca13d..f74b49d5010cde0e94c444246215e5d27ec83841 100644 (file)
@@ -7,12 +7,13 @@
 #include "journal-internal.h"
 #include "log.h"
 #include "macro.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
         unsigned n = 0;
         _cleanup_(sd_journal_closep) sd_journal*j = NULL;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY) >= 0);
 
index a43672b6e1e2cc3ca7217612caa5e688623a3379..860baca38388e0b0e50cda82b3e2b63d62331dcd 100644 (file)
@@ -5,6 +5,7 @@
 #include "log.h"
 #include "parse-util.h"
 #include "rm-rf.h"
+#include "tests.h"
 #include "util.h"
 
 int main(int argc, char *argv[]) {
@@ -12,7 +13,7 @@ int main(int argc, char *argv[]) {
         int r, i, I = 100;
         char t[] = "/tmp/journal-stream-XXXXXX";
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         if (argc >= 2) {
                 r = safe_atoi(argv[1], &I);
index 1f0c9f8f2aaf10a3c7897c3f554dd202d3146426..7b098b4ba260885ad078581e45ba9f9c94563949 100644 (file)
@@ -15,9 +15,9 @@
 #include "parse-util.h"
 #include "rm-rf.h"
 #include "util.h"
+#include "tests.h"
 
-/* This program tests skipping around in a multi-file journal.
- */
+/* This program tests skipping around in a multi-file journal. */
 
 static bool arg_keep = false;
 
@@ -274,11 +274,11 @@ static void test_sequence_numbers(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         /* journal_file_open requires a valid machine id */
         if (access("/etc/machine-id", F_OK) != 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("/etc/machine-id not found");
 
         arg_keep = argc > 1;
 
index 4e5ad1791a8e21f70aa9532fcdc0686d85cbc079..ba415fcc38375bff949eeaa4121af234fadec83b 100644 (file)
@@ -8,13 +8,14 @@
 #include "journal-internal.h"
 #include "log.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_(sd_journal_closep) sd_journal*j = NULL;
         _cleanup_free_ char *t;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(sd_journal_open(&j, 0) >= 0);
 
index ae35c91effd120c4fdd2a051decdc0aab30264f2..226c30f80a3914677918e9e71589da1f794bce6a 100644 (file)
@@ -12,6 +12,7 @@
 #include "macro.h"
 #include "parse-util.h"
 #include "rm-rf.h"
+#include "tests.h"
 #include "util.h"
 
 #define N_ENTRIES 200
@@ -68,9 +69,9 @@ int main(int argc, char *argv[]) {
 
         /* journal_file_open requires a valid machine id */
         if (access("/etc/machine-id", F_OK) != 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("/etc/machine-id not found");
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
index c1c3a82c42ecf6e46bffd2252c8542b4845434f1..8d6b4412134402fec1a111462f07c87bd655f7f6 100644 (file)
@@ -10,6 +10,7 @@
 #include "log.h"
 #include "rm-rf.h"
 #include "terminal-util.h"
+#include "tests.h"
 #include "util.h"
 
 #define N_ENTRIES 6000
@@ -62,9 +63,9 @@ int main(int argc, char *argv[]) {
 
         /* journal_file_open requires a valid machine id */
         if (access("/etc/machine-id", F_OK) != 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("/etc/machine-id not found");
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
index 69bdff67606c66bfb060381f0489f3a6eb6117e8..34f202c81da244382eb6d644504b68c516831522 100644 (file)
@@ -8,6 +8,7 @@
 #include "journal-vacuum.h"
 #include "log.h"
 #include "rm-rf.h"
+#include "tests.h"
 
 static bool arg_keep = false;
 
@@ -21,7 +22,7 @@ static void test_non_empty(void) {
         sd_id128_t fake_boot_id;
         char t[] = "/tmp/journal-XXXXXX";
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
@@ -112,7 +113,7 @@ static void test_empty(void) {
         JournalFile *f1, *f2, *f3, *f4;
         char t[] = "/tmp/journal-XXXXXX";
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
@@ -164,7 +165,7 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
 
         assert_se(data_size <= sizeof(data));
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
@@ -238,9 +239,11 @@ static void test_min_compress_size(void) {
 int main(int argc, char *argv[]) {
         arg_keep = argc > 1;
 
+        test_setup_logging(LOG_INFO);
+
         /* journal_file_open requires a valid machine id */
         if (access("/etc/machine-id", F_OK) != 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("/etc/machine-id not found");
 
         test_non_empty();
         test_empty();
index f1cbd6a4f159e12bc1051ee6861fe087dfd7608d..c45b068fd7cccfa48b0b32b193729ab791c9f9fe 100644 (file)
@@ -73,8 +73,6 @@ struct DHCP6IA {
                 struct ia_pd ia_pd;
                 struct ia_ta ia_ta;
         };
-        sd_event_source *timeout_t1;
-        sd_event_source *timeout_t2;
 
         LIST_HEAD(DHCP6Address, addresses);
 };
index ff0b0f00ce2911381bd5762712642ea6c439ec44..e004f48b4e24f441bd5eef669a5d9cfe45157d90 100644 (file)
@@ -37,7 +37,6 @@ struct sd_dhcp6_lease {
         size_t ntp_fqdn_count;
 };
 
-int dhcp6_lease_clear_timers(DHCP6IA *ia);
 int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
 DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
 
@@ -50,6 +49,7 @@ int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
 int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
 
 int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
+int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
 
 int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
 int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
index 8295d4d40400e780f9300c7aeac54f589216c4a1..f3c4e0ac881a1dd78fc4d080e736409f6dc40474 100644 (file)
@@ -18,8 +18,7 @@ static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
         siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
 }
 
-static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
-        const LLDPNeighborID *x = a, *y = b;
+int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
         int r;
 
         r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
@@ -39,7 +38,7 @@ static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
 
 const struct hash_ops lldp_neighbor_id_hash_ops = {
         .hash = lldp_neighbor_id_hash_func,
-        .compare = lldp_neighbor_id_compare_func
+        .compare = (__compar_fn_t) lldp_neighbor_id_compare_func,
 };
 
 int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
index 494bc51760a30ca696d5f11d6a6b5e32a90d5058..2241c3bd9df201a0fdd454f33d61e1f45bf25b16 100644 (file)
@@ -81,6 +81,7 @@ static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
 }
 
 extern const struct hash_ops lldp_neighbor_id_hash_ops;
+int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
 int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
 
 sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
index a99ddaae9dd65c3a3eca5c507c8876a0eb1dd9be..b306f07eb98f4ee3c3b501576d595a90bdcbae3f 100644 (file)
 
 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
 
+/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
+enum {
+        DHCP6_REQUEST_IA_NA                     = 1,
+        DHCP6_REQUEST_IA_TA                     = 2, /* currently not used */
+        DHCP6_REQUEST_IA_PD                     = 4,
+};
+
 struct sd_dhcp6_client {
         unsigned n_ref;
 
@@ -40,7 +47,9 @@ struct sd_dhcp6_client {
         uint16_t arp_type;
         DHCP6IA ia_na;
         DHCP6IA ia_pd;
-        bool prefix_delegation;
+        sd_event_source *timeout_t1;
+        sd_event_source *timeout_t2;
+        int request;
         be32_t transaction_id;
         usec_t transaction_start;
         struct sd_dhcp6_lease *lease;
@@ -325,10 +334,36 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
         return 0;
 }
 
-int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) {
+int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
+        assert_return(client, -EINVAL);
+        assert_return(delegation, -EINVAL);
+
+        *delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
+
+        return 0;
+}
+
+int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
+        assert_return(client, -EINVAL);
+
+        SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
+
+        return 0;
+}
+
+int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
         assert_return(client, -EINVAL);
+        assert_return(request, -EINVAL);
 
-        client->prefix_delegation = delegation;
+        *request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
+
+        return 0;
+}
+
+int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
+        assert_return(client, -EINVAL);
+
+        SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
 
         return 0;
 }
@@ -355,12 +390,8 @@ static void client_notify(sd_dhcp6_client *client, int event) {
 static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
         assert(client);
 
-        if (client->lease) {
-                dhcp6_lease_clear_timers(&client->lease->ia);
-                sd_dhcp6_lease_unref(client->lease);
-        }
-
-        client->lease = lease;
+        (void) sd_dhcp6_lease_unref(client->lease);
+        client->lease = sd_dhcp6_lease_ref(lease);
 }
 
 static int client_reset(sd_dhcp6_client *client) {
@@ -374,11 +405,6 @@ static int client_reset(sd_dhcp6_client *client) {
         client->transaction_id = 0;
         client->transaction_start = 0;
 
-        client->ia_na.timeout_t1 =
-                sd_event_source_unref(client->ia_na.timeout_t1);
-        client->ia_na.timeout_t2 =
-                sd_event_source_unref(client->ia_na.timeout_t2);
-
         client->retransmit_time = 0;
         client->retransmit_count = 0;
         client->timeout_resend = sd_event_source_unref(client->timeout_resend);
@@ -436,9 +462,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 if (r < 0)
                         return r;
 
-                r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
-                if (r < 0)
-                        return r;
+                if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+                        r = dhcp6_option_append_ia(&opt, &optlen,
+                                                   &client->ia_na);
+                        if (r < 0)
+                                return r;
+                }
 
                 if (client->fqdn) {
                         r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
@@ -446,7 +475,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
-                if (client->prefix_delegation) {
+                if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
                         if (r < 0)
                                 return r;
@@ -471,9 +500,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 if (r < 0)
                         return r;
 
-                r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
-                if (r < 0)
-                        return r;
+                if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+                        r = dhcp6_option_append_ia(&opt, &optlen,
+                                                   &client->lease->ia);
+                        if (r < 0)
+                                return r;
+                }
 
                 if (client->fqdn) {
                         r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
@@ -481,7 +513,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
-                if (client->prefix_delegation) {
+                if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
                         if (r < 0)
                                 return r;
@@ -495,9 +527,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
         case DHCP6_STATE_REBIND:
                 message->type = DHCP6_REBIND;
 
-                r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
-                if (r < 0)
-                        return r;
+                if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+                        r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
+                        if (r < 0)
+                                return r;
+                }
 
                 if (client->fqdn) {
                         r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
@@ -505,7 +539,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
-                if (client->prefix_delegation) {
+                if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
                         if (r < 0)
                                 return r;
@@ -562,8 +596,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         assert(client);
         assert(client->lease);
 
-        client->lease->ia.timeout_t2 =
-                sd_event_source_unref(client->lease->ia.timeout_t2);
+        client->timeout_t2 =
+                sd_event_source_unref(client->timeout_t2);
 
         log_dhcp6_client(client, "Timeout T2");
 
@@ -579,8 +613,8 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
         assert(client);
         assert(client->lease);
 
-        client->lease->ia.timeout_t1 =
-                sd_event_source_unref(client->lease->ia.timeout_t1);
+        client->timeout_t1 =
+                sd_event_source_unref(client->timeout_t1);
 
         log_dhcp6_client(client, "Timeout T1");
 
@@ -914,7 +948,7 @@ static int client_parse_message(
                         if (r < 0 && r != -ENOMSG)
                                 return r;
 
-                        r = dhcp6_lease_get_iaid(lease, &iaid_lease);
+                        r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
                         if (r < 0)
                                 return r;
 
@@ -1188,10 +1222,33 @@ static int client_receive_message(
         return 0;
 }
 
+static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
+                               uint32_t *lifetime_t2) {
+        assert_return(client, -EINVAL);
+        assert_return(client->lease, -EINVAL);
+
+        if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
+                *lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
+                *lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
+
+                return 0;
+        }
+
+        if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
+                *lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
+                *lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
+
+                return 0;
+        }
+
+        return -ENOMSG;
+}
+
 static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
         int r;
         usec_t timeout, time_now;
         char time_string[FORMAT_TIMESPAN_MAX];
+        uint32_t lifetime_t1, lifetime_t2;
 
         assert_return(client, -EINVAL);
         assert_return(client->event, -EINVAL);
@@ -1251,57 +1308,58 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
 
         case DHCP6_STATE_BOUND:
 
-                if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff ||
-                    client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) {
+                r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
+                if (r < 0)
+                        goto error;
 
+                if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
                         log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
-                                         be32toh(client->lease->ia.ia_na.lifetime_t1),
-                                         be32toh(client->lease->ia.ia_na.lifetime_t2));
+                                         lifetime_t1, lifetime_t2);
 
                         return 0;
                 }
 
-                timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC);
+                timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
 
                 log_dhcp6_client(client, "T1 expires in %s",
                                  format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
 
                 r = sd_event_add_time(client->event,
-                                      &client->lease->ia.timeout_t1,
+                                      &client->timeout_t1,
                                       clock_boottime_or_monotonic(), time_now + timeout,
                                       10 * USEC_PER_SEC, client_timeout_t1,
                                       client);
                 if (r < 0)
                         goto error;
 
-                r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
+                r = sd_event_source_set_priority(client->timeout_t1,
                                                  client->event_priority);
                 if (r < 0)
                         goto error;
 
-                r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
+                r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
                 if (r < 0)
                         goto error;
 
-                timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC);
+                timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
 
                 log_dhcp6_client(client, "T2 expires in %s",
                                  format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
 
                 r = sd_event_add_time(client->event,
-                                      &client->lease->ia.timeout_t2,
+                                      &client->timeout_t2,
                                       clock_boottime_or_monotonic(), time_now + timeout,
                                       10 * USEC_PER_SEC, client_timeout_t2,
                                       client);
                 if (r < 0)
                         goto error;
 
-                r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
+                r = sd_event_source_set_priority(client->timeout_t2,
                                                  client->event_priority);
                 if (r < 0)
                         goto error;
 
-                r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
+                r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
                 if (r < 0)
                         goto error;
 
@@ -1363,6 +1421,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
         if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
                 return -EBUSY;
 
+        if (!client->information_request && !client->request)
+                return -EINVAL;
+
         r = client_reset(client);
         if (r < 0)
                 return r;
@@ -1461,6 +1522,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
         client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
         client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
         client->ifindex = -1;
+        client->request = DHCP6_REQUEST_IA_NA;
         client->fd = -1;
 
         client->req_opts_len = ELEMENTSOF(default_req_opts);
index 54283133cb0b592042108ea578ce23861029a86e..15fec2d851c7f121336fc39011b8d500ea72d9c7 100644 (file)
 #include "strv.h"
 #include "util.h"
 
-int dhcp6_lease_clear_timers(DHCP6IA *ia) {
-        assert_return(ia, -EINVAL);
-
-        ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
-        ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
-
-        return 0;
-}
-
 int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
         DHCP6Address *addr;
         uint32_t valid = 0, t;
@@ -48,8 +39,6 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
         if (!ia)
                 return NULL;
 
-        dhcp6_lease_clear_timers(ia);
-
         while (ia->addresses) {
                 address = ia->addresses;
 
@@ -136,6 +125,15 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
         return 0;
 }
 
+int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
+        assert_return(lease, -EINVAL);
+        assert_return(iaid, -EINVAL);
+
+        *iaid = lease->pd.ia_pd.id;
+
+        return 0;
+}
+
 int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
                                uint32_t *lifetime_preferred,
                                uint32_t *lifetime_valid) {
index e3e6ac34d81970fa6f52dacfc840a38ef10202b3..e60aebc627763720c71ba256cad5cd0d2140cead 100644 (file)
@@ -371,10 +371,8 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
         return 0;
 }
 
-static int neighbor_compare_func(const void *a, const void *b) {
-        const sd_lldp_neighbor * const*x = a, * const *y = b;
-
-        return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id);
+static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
+        return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
 }
 
 static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
@@ -462,7 +460,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
         assert((size_t) k == hashmap_size(lldp->neighbor_by_id));
 
         /* Return things in a stable order */
-        qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func);
+        typesafe_qsort(l, k, neighbor_compare_func);
         *ret = l;
 
         return k;
index 079e760996f63c3ff28682c6cbedf19ebb7023a8..302eea2c30fa7fb09e5516d2174a73618f3f4ed6 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "in-addr-util.h"
 #include "netlink-util.h"
+#include "tests.h"
 #include "util.h"
 
 static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) {
@@ -83,9 +84,7 @@ static int test_acd(const char *ifname, const char *address) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         if (argc == 3)
                 return test_acd(argv[1], argv[2]);
index 0e257633b85dd86d7f35e0013d4668126aaf7db1..30dc36140f6abdc0da605f5e936e8d679b61082b 100644 (file)
@@ -16,6 +16,7 @@
 #include "dhcp-internal.h"
 #include "dhcp-protocol.h"
 #include "fd-util.h"
+#include "tests.h"
 #include "util.h"
 
 static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
@@ -524,9 +525,7 @@ static void test_addr_acq(sd_event *e) {
 int main(int argc, char *argv[]) {
         _cleanup_(sd_event_unrefp) sd_event *e;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(sd_event_new(&e) >= 0);
 
index 815b11e9974a5cb0b859c10efa5d477c4fb1f3d8..ea998939bc48729adf2c7e5dfa07220142e05b64 100644 (file)
@@ -9,6 +9,7 @@
 #include "sd-event.h"
 
 #include "dhcp-server-internal.h"
+#include "tests.h"
 
 static void test_pool(struct in_addr *address, unsigned size, int ret) {
         _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
@@ -54,9 +55,8 @@ static int test_basic(sd_event *event) {
         test_pool(&address_lo, 1, 0);
 
         r = sd_dhcp_server_start(server);
-
         if (r == -EPERM)
-                return EXIT_TEST_SKIP;
+                return log_info_errno(r, "sd_dhcp_server_start failed: %m");
         assert_se(r >= 0);
 
         assert_se(sd_dhcp_server_start(server) == -EBUSY);
@@ -229,15 +229,13 @@ int main(int argc, char *argv[]) {
         _cleanup_(sd_event_unrefp) sd_event *e;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(sd_event_new(&e) >= 0);
 
         r = test_basic(e);
         if (r != 0)
-                return r;
+                return log_tests_skipped("cannot start dhcp server");
 
         test_message_handler();
         test_client_id_hash();
index 27c0002fe2853132905aac2d1078e96238f89ff8..5ec8403df01aa5c67590c83d9010ef34a04100c6 100644 (file)
@@ -19,6 +19,7 @@
 #include "fd-util.h"
 #include "macro.h"
 #include "socket-util.h"
+#include "tests.h"
 #include "virt.h"
 
 static struct ether_addr mac_addr = {
@@ -36,6 +37,7 @@ static uint8_t test_duid[14] = { };
 
 static int test_client_basic(sd_event *e) {
         sd_dhcp6_client *client;
+        int v;
 
         if (verbose)
                 printf("* %s\n", __FUNCTION__);
@@ -67,6 +69,36 @@ static int test_client_basic(sd_event *e) {
         assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
         assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
 
+        assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
+        v = 0;
+        assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
+        assert_se(v);
+        assert_se(sd_dhcp6_client_set_information_request(client, 0) >= 0);
+        v = 42;
+        assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
+        assert_se(v == 0);
+
+        v = 0;
+        assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+        assert_se(v);
+        v = 0;
+        assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
+        assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+        assert_se(v);
+        v = 42;
+        assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
+        assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+        assert_se(v);
+
+        assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
+        assert_se(sd_dhcp6_client_set_prefix_delegation(client, 1) >= 0);
+        v = 0;
+        assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+        assert_se(v);
+        v = 0;
+        assert_se(sd_dhcp6_client_get_prefix_delegation(client, &v) >= 0);
+        assert_se(v);
+
         assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
 
         assert_se(sd_dhcp6_client_detach_event(client) >= 0);
@@ -861,7 +893,7 @@ static int test_client_solicit(sd_event *e) {
         sd_dhcp6_client *client;
         usec_t time_now = now(clock_boottime_or_monotonic());
         struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
-        int val = true;
+        int val;
 
         if (verbose)
                 printf("* %s\n", __FUNCTION__);
@@ -878,10 +910,10 @@ static int test_client_solicit(sd_event *e) {
         assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
 
         assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
-        assert_se(val == false);
-        assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
+        assert_se(val == 0);
+        assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
         assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
-        assert_se(val == true);
+        assert_se(val);
 
         assert_se(sd_dhcp6_client_set_callback(client,
                                                test_client_information_cb, e) >= 0);
@@ -910,9 +942,7 @@ int main(int argc, char *argv[]) {
 
         assert_se(sd_event_new(&e) >= 0);
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_client_basic(e);
         test_option(e);
index 125133f0393502ea1a3cae1c722aeafeb3871dd0..fd827ff40144e37cadef649df6fd22cddc03eeb4 100644 (file)
@@ -15,6 +15,7 @@
 #include "netlink-util.h"
 #include "parse-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
@@ -95,9 +96,7 @@ static int test_ll(const char *ifname, const char *seed) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         if (argc == 2)
                 return test_ll(argv[1], NULL);
index ee9cce02a895cafed743ebacda07ea79f272e421..d9c803f899dc00efc46a5ffadb178017fe3a3b42 100644 (file)
@@ -15,6 +15,7 @@
 #include "arp-util.h"
 #include "fd-util.h"
 #include "socket-util.h"
+#include "tests.h"
 #include "util.h"
 
 static bool verbose = false;
@@ -193,9 +194,7 @@ static void test_basic_request(sd_event *e) {
 int main(int argc, char *argv[]) {
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(sd_event_new(&e) >= 0);
 
index d5a023766382b47fa2dd4da750762415239350b7..c8870fad0d56723adb239127f0ad368aa556987e 100644 (file)
@@ -13,6 +13,7 @@
 #include "icmp6-util.h"
 #include "socket-util.h"
 #include "strv.h"
+#include "tests.h"
 
 static struct ether_addr mac_addr = {
         .ether_addr_octet = { 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 }
@@ -357,9 +358,7 @@ static void test_ra(void) {
 
 int main(int argc, char *argv[]) {
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_radv_prefix();
         test_radv();
index b9d0e7dc90e3648e358079c671e0c4cc24e2c1f7..70f289bcb560f2d5f397c67b63131d269d346c75 100644 (file)
@@ -14,6 +14,7 @@
 #include "socket-util.h"
 #include "strv.h"
 #include "ndisc-internal.h"
+#include "tests.h"
 
 static struct ether_addr mac_addr = {
         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
@@ -407,9 +408,7 @@ static void test_timeout(void) {
 
 int main(int argc, char *argv[]) {
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_rs();
         test_timeout();
index 070fd6c633b86e6fd06f7fff8f9cd567ac9dc0df..e3716a68d87bc527b90ce175f39124ed26e67a54 100644 (file)
@@ -58,6 +58,7 @@ libsystemd_sources = files('''
         sd-device/device-util.h
         sd-device/sd-device.c
         sd-hwdb/hwdb-internal.h
+        sd-hwdb/hwdb-util.c
         sd-hwdb/hwdb-util.h
         sd-hwdb/sd-hwdb.c
         sd-netlink/generic-netlink.c
index 6ac57d48e3c4b7456a7e17f1c98eb4e0ff3ae023..37b851b94ce37b61056ba70be4ac51861e871482 100644 (file)
@@ -760,15 +760,8 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n
         return -EINVAL;
 }
 
-static int match_component_compare(const void *a, const void *b) {
-        const struct bus_match_component *x = a, *y = b;
-
-        if (x->type < y->type)
-                return -1;
-        if (x->type > y->type)
-                return 1;
-
-        return 0;
+static int match_component_compare(const struct bus_match_component *a, const struct bus_match_component *b) {
+        return CMP(a->type, b->type);
 }
 
 void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
@@ -901,7 +894,7 @@ int bus_match_parse(
         }
 
         /* Order the whole thing, so that we always generate the same tree */
-        qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
+        typesafe_qsort(components, n_components, match_component_compare);
 
         /* Check for duplicates */
         for (i = 0; i+1 < n_components; i++)
index f3ff856e42c80192ca9c58b98aa3838f7b2aaadd..2ba6eaee7d17871deccad944dfb95a13289fabdf 100644 (file)
@@ -16,6 +16,7 @@
 #include "format-util.h"
 #include "log.h"
 #include "macro.h"
+#include "tests.h"
 #include "util.h"
 
 static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
@@ -509,11 +510,11 @@ int main(int argc, char *argv[]) {
         void *p;
         int q, r;
 
+        test_setup_logging(LOG_INFO);
+
         r = server_init(&bus);
-        if (r < 0) {
-                log_info("Failed to connect to bus, skipping tests.");
-                return EXIT_TEST_SKIP;
-        }
+        if (r < 0)
+                return log_tests_skipped("Failed to connect to bus");
 
         log_info("Initialized...");
 
index d1d962ebb2d0cdcf9d7c2dafaa66f950e53f5989..975d3f97dd9d03bf9956cadb48b26c27b6e70123 100644 (file)
@@ -8,6 +8,7 @@
 #include "bus-message.h"
 #include "bus-util.h"
 #include "refcnt.h"
+#include "tests.h"
 
 static void test_bus_new(void) {
         _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
@@ -59,17 +60,12 @@ static void test_bus_new_signal(void) {
 }
 
 int main(int argc, char **argv) {
-        int r;
-
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         test_bus_new();
-        r = test_bus_open();
-        if (r < 0) {
-                log_info("Failed to connect to bus, skipping tests.");
-                return EXIT_TEST_SKIP;
-        }
+
+        if (test_bus_open() < 0)
+                return log_tests_skipped("Failed to connect to bus");
 
         test_bus_new_method_call();
         test_bus_new_signal();
index 69f1f3e34501e078ea1deee759de4c357fe44b99..c02c459663b883f68c7c652704f274df9859b0b6 100644 (file)
@@ -5,19 +5,16 @@
 #include "bus-dump.h"
 #include "bus-util.h"
 #include "cgroup-util.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
-        if (cg_unified_flush() == -ENOMEDIUM) {
-                log_info("Skipping test: /sys/fs/cgroup/ not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (cg_unified_flush() == -ENOMEDIUM)
+                return log_tests_skipped("/sys/fs/cgroup/ not available");
 
         r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
         log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG, r, "sd_bus_creds_new_from_pid: %m");
index 33f4d1ee0b206eda1122aca80831669aa9653053..ae418efa8b34c6fb3f3b69cb1a252ac4c55b1526 100644 (file)
@@ -13,6 +13,7 @@
 #include "bus-message.h"
 #include "bus-util.h"
 #include "macro.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_bus_gvariant_is_fixed_size(void) {
@@ -113,16 +114,16 @@ static void test_bus_gvariant_get_alignment(void) {
         assert_se(bus_gvariant_get_alignment("((t)(t))") == 8);
 }
 
-static void test_marshal(void) {
+static int test_marshal(void) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        _cleanup_free_ void *blob;
+        _cleanup_free_ void *blob = NULL;
         size_t sz;
         int r;
 
         r = sd_bus_open_user(&bus);
         if (r < 0)
-                exit(EXIT_TEST_SKIP);
+                return log_tests_skipped_errno(r, "Failed to connect to bus");
 
         bus->message_version = 2; /* dirty hack to enable gvariant */
 
@@ -194,14 +195,16 @@ static void test_marshal(void) {
 
         assert_se(sd_bus_message_seal(m, 4712, 0) >= 0);
         assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
+
+        return EXIT_SUCCESS;
 }
 
 int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_INFO);
 
         test_bus_gvariant_is_fixed_size();
         test_bus_gvariant_get_size();
         test_bus_gvariant_get_alignment();
-        test_marshal();
 
-        return 0;
+        return test_marshal();
 }
index cc1b61ce58538f745c48e8e2a313db4ef2f0e218..7e113b179e0e06e274731cca9f99ab4dd3bd41ca 100644 (file)
@@ -21,6 +21,7 @@
 #include "fd-util.h"
 #include "hexdecoct.h"
 #include "log.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_bus_path_encode_unique(void) {
@@ -120,9 +121,11 @@ int main(int argc, char *argv[]) {
         double dbl;
         uint64_t u64;
 
+        test_setup_logging(LOG_INFO);
+
         r = sd_bus_default_user(&bus);
         if (r < 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("Failed to connect to bus");
 
         r = sd_bus_message_new_method_call(bus, &m, "foobar.waldo", "/", "foobar.waldo", "Piep");
         assert_se(r >= 0);
index 2f1d057eb9e4380b72efa0eb15c4bbc225f87ac1..c56b39437bccf89352bcb86763c95a373ea169fc 100644 (file)
@@ -6,6 +6,7 @@
 #include "bus-util.h"
 #include "log.h"
 #include "macro.h"
+#include "tests.h"
 
 static bool mask[32];
 
@@ -77,9 +78,11 @@ int main(int argc, char *argv[]) {
         sd_bus_slot slots[19];
         int r;
 
+        test_setup_logging(LOG_INFO);
+
         r = sd_bus_open_user(&bus);
         if (r < 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("Failed to connect to bus");
 
         assert_se(match_add(slots, &root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
         assert_se(match_add(slots, &root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
index b75703f14ff254f4eed214c2567198edf0052b84..a2782cd1d50a330c29eb403de8bf955aef21fb1d 100644 (file)
@@ -6,6 +6,7 @@
 #include "sd-bus.h"
 
 #include "macro.h"
+#include "tests.h"
 
 static bool track_cb_called_x = false;
 static bool track_cb_called_y = false;
@@ -47,14 +48,14 @@ int main(int argc, char *argv[]) {
         const char *unique;
         int r;
 
+        test_setup_logging(LOG_INFO);
+
         r = sd_event_default(&event);
         assert_se(r >= 0);
 
         r = sd_bus_open_user(&a);
-        if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
-                log_info("Failed to connect to bus, skipping tests.");
-                return EXIT_TEST_SKIP;
-        }
+        if (IN_SET(r, -ECONNREFUSED, -ENOENT))
+                return log_tests_skipped("Failed to connect to bus");
         assert_se(r >= 0);
 
         r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL);
index 56a953d33b0be757f828d2f0ff3425cf4c575d08..87411bfdd80480f9920f2b8cf2172faafbba2f22 100644 (file)
@@ -9,6 +9,7 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
+sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices);
 
 #define FOREACH_DEVICE_AND_SUBSYSTEM(enumerator, device)       \
         for (device = device_enumerator_get_first(enumerator); \
index e1f60126b3ab470cb923e96496e7b2ebb93a7cc9..c7e5bf4431f5ee0d303c7ce4853fa8b6d73e605c 100644 (file)
@@ -7,7 +7,6 @@
 #include "device-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
-#include "prioq.h"
 #include "set.h"
 #include "string-util.h"
 #include "strv.h"
@@ -26,7 +25,8 @@ struct sd_device_enumerator {
         unsigned n_ref;
 
         DeviceEnumerationType type;
-        Prioq *devices;
+        sd_device **devices;
+        size_t n_devices, n_allocated, current_device_index;
         bool scan_uptodate;
 
         Set *match_subsystem;
@@ -60,15 +60,14 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
 }
 
 static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
-        sd_device *device;
+        size_t i;
 
         assert(enumerator);
 
-        while ((device = prioq_pop(enumerator->devices)))
-                sd_device_unref(device);
-
-        prioq_free(enumerator->devices);
+        for (i = 0; i < enumerator->n_devices; i++)
+                sd_device_unref(enumerator->devices[i]);
 
+        free(enumerator->devices);
         set_free_free(enumerator->match_subsystem);
         set_free_free(enumerator->nomatch_subsystem);
         hashmap_free_free_free(enumerator->match_sysattr);
@@ -250,10 +249,11 @@ int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator)
         return 0;
 }
 
-static int device_compare(const void *_a, const void *_b) {
-        sd_device *a = (sd_device *)_a, *b = (sd_device *)_b;
+static int device_compare(sd_device * const *_a, sd_device * const *_b) {
+        sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b;
         const char *devpath_a, *devpath_b, *sound_a;
         bool delay_a, delay_b;
+        int r;
 
         assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
         assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
@@ -294,27 +294,21 @@ static int device_compare(const void *_a, const void *_b) {
         /* md and dm devices are enumerated after all other devices */
         delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-");
         delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-");
-        if (delay_a != delay_b)
-                return delay_a - delay_b;
+        r = CMP(delay_a, delay_b);
+        if (r != 0)
+                return r;
 
         return strcmp(devpath_a, devpath_b);
 }
 
 int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
-        int r;
-
         assert_return(enumerator, -EINVAL);
         assert_return(device, -EINVAL);
 
-        r = prioq_ensure_allocated(&enumerator->devices, device_compare);
-        if (r < 0)
-                return r;
-
-        r = prioq_put(enumerator->devices, device, NULL);
-        if (r < 0)
-                return r;
+        if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_allocated, enumerator->n_devices + 1))
+                return -ENOMEM;
 
-        sd_device_ref(device);
+        enumerator->devices[enumerator->n_devices++] = sd_device_ref(device);
 
         return 0;
 }
@@ -484,18 +478,6 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
                         continue;
                 }
 
-                k = sd_device_get_devnum(device, &devnum);
-                if (k < 0) {
-                        r = k;
-                        continue;
-                }
-
-                k = sd_device_get_ifindex(device, &ifindex);
-                if (k < 0) {
-                        r = k;
-                        continue;
-                }
-
                 k = sd_device_get_is_initialized(device, &initialized);
                 if (k < 0) {
                         r = k;
@@ -514,7 +496,8 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
                  */
                 if (!enumerator->match_allow_uninitialized &&
                     !initialized &&
-                    (major(devnum) > 0 || ifindex > 0))
+                    (sd_device_get_devnum(device, &devnum) >= 0 ||
+                     (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0)))
                         continue;
 
                 if (!match_parent(enumerator, device))
@@ -810,8 +793,8 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
 }
 
 int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
-        sd_device *device;
         int r = 0, k;
+        size_t i;
 
         assert(enumerator);
 
@@ -819,8 +802,10 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
             enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
                 return 0;
 
-        while ((device = prioq_pop(enumerator->devices)))
-                sd_device_unref(device);
+        for (i = 0; i < enumerator->n_devices; i++)
+                sd_device_unref(enumerator->devices[i]);
+
+        enumerator->n_devices = 0;
 
         if (!set_isempty(enumerator->match_tag)) {
                 k = enumerator_scan_devices_tags(enumerator);
@@ -836,7 +821,10 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
                         r = k;
         }
 
+        typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
+
         enumerator->scan_uptodate = true;
+        enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
 
         return r;
 }
@@ -850,27 +838,29 @@ _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *
         if (r < 0)
                 return NULL;
 
-        enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
+        enumerator->current_device_index = 0;
+
+        if (enumerator->n_devices == 0)
+                return NULL;
 
-        return prioq_peek(enumerator->devices);
+        return enumerator->devices[0];
 }
 
 _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
         assert_return(enumerator, NULL);
 
         if (!enumerator->scan_uptodate ||
-            enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES)
+            enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
+            enumerator->current_device_index + 1 >= enumerator->n_devices)
                 return NULL;
 
-        sd_device_unref(prioq_pop(enumerator->devices));
-
-        return prioq_peek(enumerator->devices);
+        return enumerator->devices[++enumerator->current_device_index];
 }
 
 int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
-        sd_device *device;
         const char *subsysdir;
         int r = 0, k;
+        size_t i;
 
         assert(enumerator);
 
@@ -878,8 +868,10 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
             enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
                 return 0;
 
-        while ((device = prioq_pop(enumerator->devices)))
-                sd_device_unref(device);
+        for (i = 0; i < enumerator->n_devices; i++)
+                sd_device_unref(enumerator->devices[i]);
+
+        enumerator->n_devices = 0;
 
         /* modules */
         if (match_subsystem(enumerator, "module")) {
@@ -913,7 +905,10 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
                 }
         }
 
+        typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
+
         enumerator->scan_uptodate = true;
+        enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
 
         return r;
 }
@@ -927,33 +922,56 @@ _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerato
         if (r < 0)
                 return NULL;
 
-        enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
+        enumerator->current_device_index = 0;
+
+        if (enumerator->n_devices == 0)
+                return NULL;
 
-        return prioq_peek(enumerator->devices);
+        return enumerator->devices[0];
 }
 
 _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
         assert_return(enumerator, NULL);
 
         if (!enumerator->scan_uptodate ||
-            enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
+            enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
+            enumerator->current_device_index + 1 >= enumerator->n_devices)
                 return NULL;
 
-        sd_device_unref(prioq_pop(enumerator->devices));
-
-        return prioq_peek(enumerator->devices);
+        return enumerator->devices[++enumerator->current_device_index];
 }
 
 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
         assert_return(enumerator, NULL);
 
-        return prioq_peek(enumerator->devices);
+        if (!enumerator->scan_uptodate)
+                return NULL;
+
+        enumerator->current_device_index = 0;
+
+        if (enumerator->n_devices == 0)
+                return NULL;
+
+        return enumerator->devices[0];
 }
 
 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
         assert_return(enumerator, NULL);
 
-        sd_device_unref(prioq_pop(enumerator->devices));
+        if (!enumerator->scan_uptodate ||
+            enumerator->current_device_index + 1 >= enumerator->n_devices)
+                return NULL;
+
+        return enumerator->devices[++enumerator->current_device_index];
+}
+
+sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
+        assert(enumerator);
+        assert(ret_n_devices);
+
+        if (!enumerator->scan_uptodate)
+                return NULL;
 
-        return prioq_peek(enumerator->devices);
+        *ret_n_devices = enumerator->n_devices;
+        return enumerator->devices;
 }
index 1e41773bba06ef47f0c8c836df6f968083a24908..eb27346786239835ff49380a8b38509f0028f6c2 100644 (file)
@@ -277,6 +277,9 @@ int device_get_devnode_mode(sd_device *device, mode_t *mode) {
         if (r < 0)
                 return r;
 
+        if (device->devmode == (mode_t) -1)
+                return -ENOENT;
+
         *mode = device->devmode;
 
         return 0;
@@ -292,6 +295,9 @@ int device_get_devnode_uid(sd_device *device, uid_t *uid) {
         if (r < 0)
                 return r;
 
+        if (device->devuid == (uid_t) -1)
+                return -ENOENT;
+
         *uid = device->devuid;
 
         return 0;
@@ -327,6 +333,9 @@ int device_get_devnode_gid(sd_device *device, gid_t *gid) {
         if (r < 0)
                 return r;
 
+        if (device->devgid == (gid_t) -1)
+                return -ENOENT;
+
         *gid = device->devgid;
 
         return 0;
@@ -723,6 +732,9 @@ int device_get_watch_handle(sd_device *device, int *handle) {
         if (r < 0)
                 return r;
 
+        if (device->watch_handle < 0)
+                return -ENOENT;
+
         *handle = device->watch_handle;
 
         return 0;
index c61e98fe7264238557c52940fcb06dd2da525236..1eb71e17dbfd8bf00d86ab13a484c91d2a131943 100644 (file)
@@ -38,6 +38,10 @@ int device_new_aux(sd_device **ret) {
         *device = (sd_device) {
                 .n_ref = 1,
                 .watch_handle = -1,
+                .ifindex = -1,
+                .devmode = (mode_t) -1,
+                .devuid = (uid_t) -1,
+                .devgid = (gid_t) -1,
         };
 
         *ret = device;
@@ -575,6 +579,9 @@ _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
         if (r < 0)
                 return r;
 
+        if (device->ifindex < 0)
+                return -ENOENT;
+
         *ifindex = device->ifindex;
 
         return 0;
@@ -839,6 +846,9 @@ _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
         if (r < 0)
                 return r;
 
+        if (!device->devtype)
+                return -ENOENT;
+
         *devtype = device->devtype;
 
         return 0;
@@ -886,6 +896,9 @@ _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
         if (r < 0)
                 return r;
 
+        if (major(device->devnum) <= 0)
+                return -ENOENT;
+
         *devnum = device->devnum;
 
         return 0;
@@ -1053,6 +1066,9 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
                         return r;
         }
 
+        if (!device->sysnum)
+                return -ENOENT;
+
         *ret = device->sysnum;
 
         return 0;
@@ -1216,15 +1232,7 @@ int device_get_id_filename(sd_device *device, const char **ret) {
                 if (r < 0)
                         return r;
 
-                r = sd_device_get_devnum(device, &devnum);
-                if (r < 0)
-                        return r;
-
-                r = sd_device_get_ifindex(device, &ifindex);
-                if (r < 0)
-                        return r;
-
-                if (major(devnum) > 0) {
+                if (sd_device_get_devnum(device, &devnum) >= 0) {
                         assert(subsystem);
 
                         /* use dev_t â€” b259:131072, c254:0 */
@@ -1233,7 +1241,7 @@ int device_get_id_filename(sd_device *device, const char **ret) {
                                      major(devnum), minor(devnum));
                         if (r < 0)
                                 return -ENOMEM;
-                } else if (ifindex > 0) {
+                } else if (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0) {
                         /* use netdev ifindex â€” n3 */
                         r = asprintf(&id, "n%u", ifindex);
                         if (r < 0)
@@ -1822,7 +1830,7 @@ static void device_remove_sysattr_value(sd_device *device, const char *_key) {
 
 /* set the attribute and save it in the cache. If a NULL value is passed the
  * attribute is cleared from the cache */
-_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
+_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
         _cleanup_close_ int fd = -1;
         _cleanup_free_ char *value = NULL;
         const char *syspath;
index 1f08b4d4b8cd4308638ef991040b64af65f79dbf..50074a56be81fa9f974eb6c8312252691e9135e0 100644 (file)
@@ -16,6 +16,7 @@
 #include "signal-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 static int prepare_handler(sd_event_source *s, void *userdata) {
@@ -481,9 +482,7 @@ static void test_inotify(unsigned n_create_events) {
 }
 
 int main(int argc, char *argv[]) {
-
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         test_basic();
         test_sd_event_now();
index d186c851844813e1d2d4449067cb84df37975704..d82b8c1279c2698d8d97a78c91513b0b3f7ed1af 100644 (file)
@@ -1,8 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdint.h>
+
 #include "sparse-endian.h"
-#include "util.h"
 
 #define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }
 
diff --git a/src/libsystemd/sd-hwdb/hwdb-util.c b/src/libsystemd/sd-hwdb/hwdb-util.c
new file mode 100644 (file)
index 0000000..bfb3ae0
--- /dev/null
@@ -0,0 +1,679 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hwdb-internal.h"
+#include "hwdb-util.h"
+#include "label.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "strv.h"
+
+static const char *default_hwdb_bin_dir = "/etc/udev";
+static const char * const conf_file_dirs[] = {
+        "/etc/udev/hwdb.d",
+        UDEVLIBEXECDIR "/hwdb.d",
+        NULL
+};
+
+/*
+ * Generic udev properties, key-value database based on modalias strings.
+ * Uses a Patricia/radix trie to index all matches for efficient lookup.
+ */
+
+/* in-memory trie objects */
+struct trie {
+        struct trie_node *root;
+        struct strbuf *strings;
+
+        size_t nodes_count;
+        size_t children_count;
+        size_t values_count;
+};
+
+struct trie_node {
+        /* prefix, common part for all children of this node */
+        size_t prefix_off;
+
+        /* sorted array of pointers to children nodes */
+        struct trie_child_entry *children;
+        uint8_t children_count;
+
+        /* sorted array of key-value pairs */
+        struct trie_value_entry *values;
+        size_t values_count;
+};
+
+/* children array item with char (0-255) index */
+struct trie_child_entry {
+        uint8_t c;
+        struct trie_node *child;
+};
+
+/* value array item with key-value pairs */
+struct trie_value_entry {
+        size_t key_off;
+        size_t value_off;
+        size_t filename_off;
+        uint32_t line_number;
+        uint16_t file_priority;
+};
+
+static int trie_children_cmp(const struct trie_child_entry *a, const struct trie_child_entry *b) {
+        return CMP(a->c, b->c);
+}
+
+static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
+        struct trie_child_entry *child;
+
+        /* extend array, add new entry, sort for bisection */
+        child = reallocarray(node->children, node->children_count + 1, sizeof(struct trie_child_entry));
+        if (!child)
+                return -ENOMEM;
+
+        node->children = child;
+        trie->children_count++;
+        node->children[node->children_count].c = c;
+        node->children[node->children_count].child = node_child;
+        node->children_count++;
+        typesafe_qsort(node->children, node->children_count, trie_children_cmp);
+        trie->nodes_count++;
+
+        return 0;
+}
+
+static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
+        struct trie_child_entry *child;
+        struct trie_child_entry search;
+
+        search.c = c;
+        child = typesafe_bsearch(&search, node->children, node->children_count, trie_children_cmp);
+        if (child)
+                return child->child;
+        return NULL;
+}
+
+static void trie_node_cleanup(struct trie_node *node) {
+        size_t i;
+
+        if (!node)
+                return;
+
+        for (i = 0; i < node->children_count; i++)
+                trie_node_cleanup(node->children[i].child);
+        free(node->children);
+        free(node->values);
+        free(node);
+}
+
+static void trie_free(struct trie *trie) {
+        if (!trie)
+                return;
+
+        trie_node_cleanup(trie->root);
+        strbuf_cleanup(trie->strings);
+        free(trie);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free);
+
+static int trie_values_cmp(const struct trie_value_entry *a, const struct trie_value_entry *b, struct trie *trie) {
+        return strcmp(trie->strings->buf + a->key_off,
+                      trie->strings->buf + b->key_off);
+}
+
+static int trie_node_add_value(struct trie *trie, struct trie_node *node,
+                               const char *key, const char *value,
+                               const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) {
+        ssize_t k, v, fn = 0;
+        struct trie_value_entry *val;
+
+        k = strbuf_add_string(trie->strings, key, strlen(key));
+        if (k < 0)
+                return k;
+        v = strbuf_add_string(trie->strings, value, strlen(value));
+        if (v < 0)
+                return v;
+
+        if (!compat) {
+                fn = strbuf_add_string(trie->strings, filename, strlen(filename));
+                if (fn < 0)
+                        return fn;
+        }
+
+        if (node->values_count) {
+                struct trie_value_entry search = {
+                        .key_off = k,
+                        .value_off = v,
+                };
+
+                val = typesafe_bsearch_r(&search, node->values, node->values_count, trie_values_cmp, trie);
+                if (val) {
+                        /* At this point we have 2 identical properties on the same match-string.
+                         * Since we process files in order, we just replace the previous value. */
+                        val->value_off = v;
+                        val->filename_off = fn;
+                        val->file_priority = file_priority;
+                        val->line_number = line_number;
+                        return 0;
+                }
+        }
+
+        /* extend array, add new entry, sort for bisection */
+        val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry));
+        if (!val)
+                return -ENOMEM;
+        trie->values_count++;
+        node->values = val;
+        node->values[node->values_count] = (struct trie_value_entry) {
+                .key_off = k,
+                .value_off = v,
+                .filename_off = fn,
+                .file_priority = file_priority,
+                .line_number = line_number,
+        };
+        node->values_count++;
+        typesafe_qsort_r(node->values, node->values_count, trie_values_cmp, trie);
+        return 0;
+}
+
+static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
+                       const char *key, const char *value,
+                       const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) {
+        size_t i = 0;
+        int r = 0;
+
+        for (;;) {
+                size_t p;
+                uint8_t c;
+                struct trie_node *child;
+
+                for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
+                        _cleanup_free_ struct trie_node *new_child = NULL;
+                        _cleanup_free_ char *s = NULL;
+                        ssize_t off;
+
+                        if (c == search[i + p])
+                                continue;
+
+                        /* split node */
+                        new_child = new(struct trie_node, 1);
+                        if (!new_child)
+                                return -ENOMEM;
+
+                        /* move values from parent to child */
+                        *new_child = (struct trie_node) {
+                                .prefix_off = node->prefix_off + p+1,
+                                .children = node->children,
+                                .children_count = node->children_count,
+                                .values = node->values,
+                                .values_count = node->values_count,
+                        };
+
+                        /* update parent; use strdup() because the source gets realloc()d */
+                        s = strndup(trie->strings->buf + node->prefix_off, p);
+                        if (!s)
+                                return -ENOMEM;
+
+                        off = strbuf_add_string(trie->strings, s, p);
+                        if (off < 0)
+                                return off;
+
+                        *node = (struct trie_node) {
+                                .prefix_off = off,
+                        };
+                        r = node_add_child(trie, node, new_child, c);
+                        if (r < 0)
+                                return r;
+
+                        new_child = NULL; /* avoid cleanup */
+                        break;
+                }
+                i += p;
+
+                c = search[i];
+                if (c == '\0')
+                        return trie_node_add_value(trie, node, key, value, filename, file_priority, line_number, compat);
+
+                child = node_lookup(node, c);
+                if (!child) {
+                        _cleanup_free_ struct trie_node *new_child = NULL;
+                        ssize_t off;
+
+                        /* new child */
+                        new_child = new(struct trie_node, 1);
+                        if (!new_child)
+                                return -ENOMEM;
+
+                        off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
+                        if (off < 0)
+                                return off;
+
+                        *new_child = (struct trie_node) {
+                                .prefix_off = off,
+                        };
+
+                        r = node_add_child(trie, node, new_child, c);
+                        if (r < 0)
+                                return r;
+
+                        child = TAKE_PTR(new_child);
+                        return trie_node_add_value(trie, child, key, value, filename, file_priority, line_number, compat);
+                }
+
+                node = child;
+                i++;
+        }
+}
+
+struct trie_f {
+        FILE *f;
+        struct trie *trie;
+        uint64_t strings_off;
+
+        uint64_t nodes_count;
+        uint64_t children_count;
+        uint64_t values_count;
+};
+
+/* calculate the storage space for the nodes, children arrays, value arrays */
+static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node, bool compat) {
+        uint64_t i;
+
+        for (i = 0; i < node->children_count; i++)
+                trie_store_nodes_size(trie, node->children[i].child, compat);
+
+        trie->strings_off += sizeof(struct trie_node_f);
+        for (i = 0; i < node->children_count; i++)
+                trie->strings_off += sizeof(struct trie_child_entry_f);
+        for (i = 0; i < node->values_count; i++)
+                trie->strings_off += compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f);
+}
+
+static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, bool compat) {
+        uint64_t i;
+        struct trie_node_f n = {
+                .prefix_off = htole64(trie->strings_off + node->prefix_off),
+                .children_count = node->children_count,
+                .values_count = htole64(node->values_count),
+        };
+        _cleanup_free_ struct trie_child_entry_f *children = NULL;
+        int64_t node_off;
+
+        if (node->children_count) {
+                children = new(struct trie_child_entry_f, node->children_count);
+                if (!children)
+                        return -ENOMEM;
+        }
+
+        /* post-order recursion */
+        for (i = 0; i < node->children_count; i++) {
+                int64_t child_off;
+
+                child_off = trie_store_nodes(trie, node->children[i].child, compat);
+                if (child_off < 0)
+                        return child_off;
+
+                children[i] = (struct trie_child_entry_f) {
+                        .c = node->children[i].c,
+                        .child_off = htole64(child_off),
+                };
+        }
+
+        /* write node */
+        node_off = ftello(trie->f);
+        fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
+        trie->nodes_count++;
+
+        /* append children array */
+        if (node->children_count) {
+                fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
+                trie->children_count += node->children_count;
+        }
+
+        /* append values array */
+        for (i = 0; i < node->values_count; i++) {
+                struct trie_value_entry2_f v = {
+                        .key_off = htole64(trie->strings_off + node->values[i].key_off),
+                        .value_off = htole64(trie->strings_off + node->values[i].value_off),
+                        .filename_off = htole64(trie->strings_off + node->values[i].filename_off),
+                        .line_number = htole32(node->values[i].line_number),
+                        .file_priority = htole16(node->values[i].file_priority),
+                };
+
+                fwrite(&v, compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f), 1, trie->f);
+        }
+        trie->values_count += node->values_count;
+
+        return node_off;
+}
+
+static int trie_store(struct trie *trie, const char *filename, bool compat) {
+        struct trie_f t = {
+                .trie = trie,
+        };
+        _cleanup_free_ char *filename_tmp = NULL;
+        int64_t pos;
+        int64_t root_off;
+        int64_t size;
+        struct trie_header_f h = {
+                .signature = HWDB_SIG,
+                .tool_version = htole64(atoi(PACKAGE_VERSION)),
+                .header_size = htole64(sizeof(struct trie_header_f)),
+                .node_size = htole64(sizeof(struct trie_node_f)),
+                .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
+                .value_entry_size = htole64(compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f)),
+        };
+        int r;
+
+        /* calculate size of header, nodes, children entries, value entries */
+        t.strings_off = sizeof(struct trie_header_f);
+        trie_store_nodes_size(&t, trie->root, compat);
+
+        r = fopen_temporary(filename, &t.f, &filename_tmp);
+        if (r < 0)
+                return r;
+        fchmod(fileno(t.f), 0444);
+
+        /* write nodes */
+        if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
+                goto error_fclose;
+
+        root_off = trie_store_nodes(&t, trie->root, compat);
+        h.nodes_root_off = htole64(root_off);
+        pos = ftello(t.f);
+        h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
+
+        /* write string buffer */
+        fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
+        h.strings_len = htole64(trie->strings->len);
+
+        /* write header */
+        size = ftello(t.f);
+        h.file_size = htole64(size);
+        if (fseeko(t.f, 0, SEEK_SET) < 0)
+                goto error_fclose;
+        fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
+
+        if (ferror(t.f))
+                goto error_fclose;
+        if (fflush(t.f) < 0)
+                goto error_fclose;
+        if (fsync(fileno(t.f)) < 0)
+                goto error_fclose;
+        if (rename(filename_tmp, filename) < 0)
+                goto error_fclose;
+
+        /* write succeeded */
+        fclose(t.f);
+
+        log_debug("=== trie on-disk ===");
+        log_debug("size:             %8"PRIi64" bytes", size);
+        log_debug("header:           %8zu bytes", sizeof(struct trie_header_f));
+        log_debug("nodes:            %8"PRIu64" bytes (%8"PRIu64")",
+                  t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
+        log_debug("child pointers:   %8"PRIu64" bytes (%8"PRIu64")",
+                  t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
+        log_debug("value pointers:   %8"PRIu64" bytes (%8"PRIu64")",
+                  t.values_count * (compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f)), t.values_count);
+        log_debug("string store:     %8zu bytes", trie->strings->len);
+        log_debug("strings start:    %8"PRIu64, t.strings_off);
+        return 0;
+
+ error_fclose:
+        r = -errno;
+        fclose(t.f);
+        unlink(filename_tmp);
+        return r;
+}
+
+static int insert_data(struct trie *trie, char **match_list, char *line, const char *filename,
+                       uint16_t file_priority, uint32_t line_number, bool compat) {
+        char *value, **entry;
+
+        assert(line[0] == ' ');
+
+        value = strchr(line, '=');
+        if (!value)
+                return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+                                  "Key-value pair expected but got \"%s\", ignoring", line);
+
+        value[0] = '\0';
+        value++;
+
+        /* Replace multiple leading spaces by a single space */
+        while (isblank(line[0]) && isblank(line[1]))
+                line++;
+
+        if (isempty(line + 1) || isempty(value))
+                return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+                                  "Empty %s in \"%s=%s\", ignoring",
+                                  isempty(line + 1) ? "key" : "value",
+                                  line, value);
+
+        STRV_FOREACH(entry, match_list)
+                trie_insert(trie, trie->root, *entry, line, value, filename, file_priority, line_number, compat);
+
+        return 0;
+}
+
+static int import_file(struct trie *trie, const char *filename, uint16_t file_priority, bool compat) {
+        enum {
+                HW_NONE,
+                HW_MATCH,
+                HW_DATA,
+        } state = HW_NONE;
+        _cleanup_fclose_ FILE *f = NULL;
+        char line[LINE_MAX];
+        _cleanup_strv_free_ char **match_list = NULL;
+        uint32_t line_number = 0;
+        char *match = NULL;
+        int r = 0, err;
+
+        f = fopen(filename, "re");
+        if (!f)
+                return -errno;
+
+        while (fgets(line, sizeof(line), f)) {
+                size_t len;
+                char *pos;
+
+                ++line_number;
+
+                /* comment line */
+                if (line[0] == '#')
+                        continue;
+
+                /* strip trailing comment */
+                pos = strchr(line, '#');
+                if (pos)
+                        pos[0] = '\0';
+
+                /* strip trailing whitespace */
+                len = strlen(line);
+                while (len > 0 && isspace(line[len-1]))
+                        len--;
+                line[len] = '\0';
+
+                switch (state) {
+                case HW_NONE:
+                        if (len == 0)
+                                break;
+
+                        if (line[0] == ' ') {
+                                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+                                           "Match expected but got indented property \"%s\", ignoring line", line);
+                                r = -EINVAL;
+                                break;
+                        }
+
+                        /* start of record, first match */
+                        state = HW_MATCH;
+
+                        match = strdup(line);
+                        if (!match)
+                                return -ENOMEM;
+
+                        err = strv_consume(&match_list, match);
+                        if (err < 0)
+                                return err;
+
+                        break;
+
+                case HW_MATCH:
+                        if (len == 0) {
+                                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+                                           "Property expected, ignoring record with no properties");
+                                r = -EINVAL;
+                                state = HW_NONE;
+                                strv_clear(match_list);
+                                break;
+                        }
+
+                        if (line[0] != ' ') {
+                                /* another match */
+                                match = strdup(line);
+                                if (!match)
+                                        return -ENOMEM;
+
+                                err = strv_consume(&match_list, match);
+                                if (err < 0)
+                                        return err;
+
+                                break;
+                        }
+
+                        /* first data */
+                        state = HW_DATA;
+                        err = insert_data(trie, match_list, line, filename, file_priority, line_number, compat);
+                        if (err < 0)
+                                r = err;
+                        break;
+
+                case HW_DATA:
+                        if (len == 0) {
+                                /* end of record */
+                                state = HW_NONE;
+                                strv_clear(match_list);
+                                break;
+                        }
+
+                        if (line[0] != ' ') {
+                                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+                                           "Property or empty line expected, got \"%s\", ignoring record", line);
+                                r = -EINVAL;
+                                state = HW_NONE;
+                                strv_clear(match_list);
+                                break;
+                        }
+
+                        err = insert_data(trie, match_list, line, filename, file_priority, line_number, compat);
+                        if (err < 0)
+                                r = err;
+                        break;
+                };
+        }
+
+        if (state == HW_MATCH)
+                log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+                           "Property expected, ignoring record with no properties");
+
+        return r;
+}
+
+int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat) {
+        _cleanup_free_ char *hwdb_bin = NULL;
+        _cleanup_(trie_freep) struct trie *trie = NULL;
+        _cleanup_strv_free_ char **files = NULL;
+        char **f;
+        uint16_t file_priority = 1;
+        int r = 0, err;
+
+        /* The argument 'compat' controls the format version of database. If false, then hwdb.bin will be created with
+         * additional information such that priority, line number, and filename of database source. If true, then hwdb.bin
+         * will be created without the information. systemd-hwdb command should set the argument false, and 'udevadm hwdb'
+         * command should set it true. */
+
+        trie = new0(struct trie, 1);
+        if (!trie)
+                return -ENOMEM;
+
+        /* string store */
+        trie->strings = strbuf_new();
+        if (!trie->strings)
+                return -ENOMEM;
+
+        /* index */
+        trie->root = new0(struct trie_node, 1);
+        if (!trie->root)
+                return -ENOMEM;
+
+        trie->nodes_count++;
+
+        err = conf_files_list_strv(&files, ".hwdb", root, 0, conf_file_dirs);
+        if (err < 0)
+                return log_error_errno(err, "Failed to enumerate hwdb files: %m");
+
+        STRV_FOREACH(f, files) {
+                log_debug("Reading file \"%s\"", *f);
+                err = import_file(trie, *f, file_priority++, compat);
+                if (err < 0 && strict)
+                        r = err;
+        }
+
+        strbuf_complete(trie->strings);
+
+        log_debug("=== trie in-memory ===");
+        log_debug("nodes:            %8zu bytes (%8zu)",
+                  trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
+        log_debug("children arrays:  %8zu bytes (%8zu)",
+                  trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
+        log_debug("values arrays:    %8zu bytes (%8zu)",
+                  trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
+        log_debug("strings:          %8zu bytes",
+                  trie->strings->len);
+        log_debug("strings incoming: %8zu bytes (%8zu)",
+                  trie->strings->in_len, trie->strings->in_count);
+        log_debug("strings dedup'ed: %8zu bytes (%8zu)",
+                  trie->strings->dedup_len, trie->strings->dedup_count);
+
+        hwdb_bin = path_join(root, hwdb_bin_dir ?: default_hwdb_bin_dir, "hwdb.bin");
+        if (!hwdb_bin)
+                return -ENOMEM;
+
+        mkdir_parents_label(hwdb_bin, 0755);
+        err = trie_store(trie, hwdb_bin, compat);
+        if (err < 0)
+                return log_error_errno(err, "Failed to write database %s: %m", hwdb_bin);
+
+        err = label_fix(hwdb_bin, 0);
+        if (err < 0)
+                return err;
+
+        return r;
+}
+
+int hwdb_query(const char *modalias) {
+        _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
+        const char *key, *value;
+        int r;
+
+        assert(modalias);
+
+        r = sd_hwdb_new(&hwdb);
+        if (r < 0)
+                return r;
+
+        SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value)
+                printf("%s=%s\n", key, value);
+
+        return 0;
+}
index 43ddccdbe90035daaf55b829578f073cc0df33ab..425b4b3e1332775fca915dde69e8b0215fd80d3b 100644 (file)
@@ -1,8 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "sd-hwdb.h"
+#include <stdbool.h>
 
-#include "util.h"
+#include "sd-hwdb.h"
 
 bool hwdb_validate(sd_hwdb *hwdb);
+int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat);
+int hwdb_query(const char *modalias);
index 371dac53088dca206918c35d9752f86249b39a98..2bbbbd03e2287a43ab629e9a250047f4507a8dea 100644 (file)
@@ -20,6 +20,7 @@
 #include "hwdb-util.h"
 #include "refcnt.h"
 #include "string-util.h"
+#include "util.h"
 
 struct sd_hwdb {
         RefCount n_ref;
index 5467ba432f239df9b9f1f630de9d1bca7d0a4ca5..5c37279bd20acfe3923da6a79897ef8f5d81c4ec 100644 (file)
@@ -7,8 +7,8 @@
 #include "macro.h"
 #include "netlink-util.h"
 
-static int address_compare(const void *_a, const void *_b) {
-        const struct local_address *a = _a, *b = _b;
+static int address_compare(const struct local_address *a, const struct local_address *b) {
+        int r;
 
         /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
 
@@ -17,20 +17,17 @@ static int address_compare(const void *_a, const void *_b) {
         if (a->family == AF_INET6 && b->family == AF_INET)
                 return 1;
 
-        if (a->scope < b->scope)
-                return -1;
-        if (a->scope > b->scope)
-                return 1;
+        r = CMP(a->scope, b->scope);
+        if (r != 0)
+                return r;
 
-        if (a->metric < b->metric)
-                return -1;
-        if (a->metric > b->metric)
-                return 1;
+        r = CMP(a->metric, b->metric);
+        if (r != 0)
+                return r;
 
-        if (a->ifindex < b->ifindex)
-                return -1;
-        if (a->ifindex > b->ifindex)
-                return 1;
+        r = CMP(a->ifindex, b->ifindex);
+        if (r != 0)
+                return r;
 
         return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
 }
@@ -137,7 +134,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
                 n_list++;
         };
 
-        qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
+        typesafe_qsort(list, n_list, address_compare);
 
         *ret = TAKE_PTR(list);
 
@@ -248,8 +245,7 @@ int local_gateways(sd_netlink *context, int ifindex, int af, struct local_addres
                 n_list++;
         }
 
-        if (n_list > 0)
-                qsort(list, n_list, sizeof(struct local_address), address_compare);
+        typesafe_qsort(list, n_list, address_compare);
 
         *ret = TAKE_PTR(list);
 
index cb05d05a896c7d3216ff5f28c9e9be100132f7d3..17114265d7be965f86cb2126553cd183e1b809d3 100644 (file)
@@ -4,6 +4,7 @@
 #include "alloc-util.h"
 #include "in-addr-util.h"
 #include "local-addresses.h"
+#include "tests.h"
 
 static void print_local_addresses(struct local_address *a, unsigned n) {
         unsigned i;
@@ -20,9 +21,7 @@ int main(int argc, char *argv[]) {
         struct local_address *a;
         int n;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         a = NULL;
         n = local_addresses(NULL, 0, AF_UNSPEC, &a);
index 45763f2c99857658f0a6286a843174d457ac239b..73db709e935dcf43f6a6f7e8db21c290861a4a87 100644 (file)
@@ -18,7 +18,7 @@ struct udev_device {
         sd_device *device;
 
         /* legacy */
-        int refcount;
+        unsigned n_ref;
 
         struct udev_device *parent;
         bool parent_set;
@@ -36,4 +36,4 @@ struct udev_device {
         bool sysattrs_read;
 };
 
-struct udev_device *udev_device_new(struct udev *udev);
+struct udev_device *udev_device_new(struct udev *udev, sd_device *device);
index 22b421299a854d8a853c22373a42c2329756d869..a7868a11cb20ae1543c49ca64e35297d746efd8f 100644 (file)
@@ -200,79 +200,59 @@ int udev_device_rename(struct udev_device *udev_device, const char *name) {
 }
 
 struct udev_device *udev_device_shallow_clone(struct udev_device *old_device) {
-        struct udev_device *device;
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
         assert(old_device);
 
-        device = udev_device_new(old_device->udev);
-        if (!device)
-                return NULL;
-
-        r = device_shallow_clone(old_device->device, &device->device);
+        r = device_shallow_clone(old_device->device, &device);
         if (r < 0) {
-                udev_device_unref(device);
                 errno = -r;
                 return NULL;
         }
 
-        return device;
+        return udev_device_new(old_device->udev, device);
 }
 
 struct udev_device *udev_device_clone_with_db(struct udev_device *udev_device_old) {
-        struct udev_device *udev_device;
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
         assert(udev_device_old);
 
-        udev_device = udev_device_new(udev_device_old->udev);
-        if (!udev_device)
-                return NULL;
-
-        r = device_clone_with_db(udev_device_old->device, &udev_device->device);
+        r = device_clone_with_db(udev_device_old->device, &device);
         if (r < 0) {
-                udev_device_unref(udev_device);
                 errno = -r;
                 return NULL;
         }
 
-        return udev_device;
+        return udev_device_new(udev_device_old->udev, device);
 }
 
 struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen) {
-        struct udev_device *device;
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        device = udev_device_new(udev);
-        if (!device)
-                return NULL;
-
-        r = device_new_from_nulstr(&device->device, (uint8_t*)nulstr, buflen);
+        r = device_new_from_nulstr(&device, (uint8_t*)nulstr, buflen);
         if (r < 0) {
-                udev_device_unref(device);
                 errno = -r;
                 return NULL;
         }
 
-        return device;
+        return udev_device_new(udev, device);
 }
 
 struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action) {
-        struct udev_device *device;
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        device = udev_device_new(udev);
-        if (!device)
-                return NULL;
-
-        r = device_new_from_synthetic_event(&device->device, syspath, action);
+        r = device_new_from_synthetic_event(&device, syspath, action);
         if (r < 0) {
-                udev_device_unref(device);
                 errno = -r;
                 return NULL;
         }
 
-        return device;
+        return udev_device_new(udev, device);
 }
 
 int udev_device_copy_properties(struct udev_device *udev_device_dst, struct udev_device *udev_device_src) {
index e6d6f70510016c92b45b037df1e40613c6d42267..1c3d67a8f5cf89a766f23896c20f48cbe700593a 100644 (file)
@@ -45,8 +45,7 @@
  *
  * Returns: the kernel event sequence number, or 0 if there is no sequence number available.
  **/
-_public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
-{
+_public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) {
         const char *seqnum;
         unsigned long long ret;
         int r;
@@ -78,8 +77,7 @@ _public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_
  *
  * Returns: the dev_t number.
  **/
-_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device)
-{
+_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) {
         dev_t devnum;
         int r;
 
@@ -87,7 +85,8 @@ _public_ dev_t udev_device_get_devnum(struct udev_device *udev_device)
 
         r = sd_device_get_devnum(udev_device->device, &devnum);
         if (r < 0) {
-                errno = -r;
+                if (r != -ENOENT)
+                        errno = -r;
                 return makedev(0, 0);
         }
 
@@ -102,8 +101,7 @@ _public_ dev_t udev_device_get_devnum(struct udev_device *udev_device)
  *
  * Returns: the driver name string, or #NULL if there is no driver attached.
  **/
-_public_ const char *udev_device_get_driver(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_driver(struct udev_device *udev_device) {
         const char *driver;
         int r;
 
@@ -126,8 +124,7 @@ _public_ const char *udev_device_get_driver(struct udev_device *udev_device)
  *
  * Returns: the devtype name of the udev device, or #NULL if it cannot be determined
  **/
-_public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_devtype(struct udev_device *udev_device) {
         const char *devtype;
         int r;
 
@@ -135,7 +132,8 @@ _public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
 
         r = sd_device_get_devtype(udev_device->device, &devtype);
         if (r < 0) {
-                errno = -r;
+                if (r != -ENOENT)
+                        errno = -r;
                 return NULL;
         }
 
@@ -151,8 +149,7 @@ _public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
  *
  * Returns: the subsystem name of the udev device, or #NULL if it cannot be determined
  **/
-_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) {
         const char *subsystem;
         int r;
 
@@ -177,8 +174,7 @@ _public_ const char *udev_device_get_subsystem(struct udev_device *udev_device)
  *
  * Returns: the property string, or #NULL if there is no such property.
  **/
-_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
-{
+_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) {
         const char *value = NULL;
         int r;
 
@@ -193,16 +189,23 @@ _public_ const char *udev_device_get_property_value(struct udev_device *udev_dev
         return value;
 }
 
-struct udev_device *udev_device_new(struct udev *udev) {
+struct udev_device *udev_device_new(struct udev *udev, sd_device *device) {
         struct udev_device *udev_device;
 
-        udev_device = new0(struct udev_device, 1);
+        assert(device);
+
+        udev_device = new(struct udev_device, 1);
         if (!udev_device) {
                 errno = ENOMEM;
                 return NULL;
         }
-        udev_device->refcount = 1;
-        udev_device->udev = udev;
+
+        *udev_device = (struct udev_device) {
+                .n_ref = 1,
+                .udev = udev,
+                .device = sd_device_ref(device),
+        };
+
         udev_list_init(udev, &udev_device->properties, true);
         udev_list_init(udev, &udev_device->tags, true);
         udev_list_init(udev, &udev_device->sysattrs, true);
@@ -226,21 +229,16 @@ struct udev_device *udev_device_new(struct udev *udev) {
  * Returns: a new udev device, or #NULL, if it does not exist
  **/
 _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
-        struct udev_device *udev_device;
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        udev_device = udev_device_new(udev);
-        if (!udev_device)
-                return NULL;
-
-        r = sd_device_new_from_syspath(&udev_device->device, syspath);
+        r = sd_device_new_from_syspath(&device, syspath);
         if (r < 0) {
                 errno = -r;
-                udev_device_unref(udev_device);
                 return NULL;
         }
 
-        return udev_device;
+        return udev_device_new(udev, device);
 }
 
 /**
@@ -259,23 +257,17 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con
  *
  * Returns: a new udev device, or #NULL, if it does not exist
  **/
-_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
-{
-        struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) {
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        udev_device = udev_device_new(udev);
-        if (!udev_device)
-                return NULL;
-
-        r = sd_device_new_from_devnum(&udev_device->device, type, devnum);
+        r = sd_device_new_from_devnum(&device, type, devnum);
         if (r < 0) {
                 errno = -r;
-                udev_device_unref(udev_device);
                 return NULL;
         }
 
-        return udev_device;
+        return udev_device_new(udev, device);
 }
 
 /**
@@ -296,23 +288,17 @@ _public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char
  *
  * Returns: a new udev device, or #NULL, if it does not exist
  **/
-_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id)
-{
-        struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) {
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        udev_device = udev_device_new(udev);
-        if (!udev_device)
-                return NULL;
-
-        r = sd_device_new_from_device_id(&udev_device->device, id);
+        r = sd_device_new_from_device_id(&device, id);
         if (r < 0) {
                 errno = -r;
-                udev_device_unref(udev_device);
                 return NULL;
         }
 
-        return udev_device;
+        return udev_device_new(udev, device);
 }
 
 /**
@@ -330,23 +316,17 @@ _public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, c
  *
  * Returns: a new udev device, or #NULL, if it does not exist
  **/
-_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
-{
-        struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) {
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        udev_device = udev_device_new(udev);
-        if (!udev_device)
-                return NULL;
-
-        r = sd_device_new_from_subsystem_sysname(&udev_device->device, subsystem, sysname);
+        r = sd_device_new_from_subsystem_sysname(&device, subsystem, sysname);
         if (r < 0) {
                 errno = -r;
-                udev_device_unref(udev_device);
                 return NULL;
         }
 
-        return udev_device;
+        return udev_device_new(udev, device);
 }
 
 /**
@@ -363,47 +343,32 @@ _public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev
  *
  * Returns: a new udev device, or #NULL, if it does not exist
  **/
-_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev)
-{
-        struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) {
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
-        udev_device = udev_device_new(udev);
-        if (!udev_device)
-                return NULL;
-
-        r = device_new_from_strv(&udev_device->device, environ);
+        r = device_new_from_strv(&device, environ);
         if (r < 0) {
                 errno = -r;
-                udev_device_unref(udev_device);
                 return NULL;
         }
 
-        return udev_device;
+        return udev_device_new(udev, device);
 }
 
-static struct udev_device *device_new_from_parent(struct udev_device *child)
-{
-        struct udev_device *parent;
+static struct udev_device *device_new_from_parent(struct udev_device *child) {
+        sd_device *parent;
         int r;
 
         assert_return_errno(child, NULL, EINVAL);
 
-        parent = udev_device_new(child->udev);
-        if (!parent)
-                return NULL;
-
-        r = sd_device_get_parent(child->device, &parent->device);
+        r = sd_device_get_parent(child->device, &parent);
         if (r < 0) {
                 errno = -r;
-                udev_device_unref(parent);
                 return NULL;
         }
 
-        /* the parent is unref'ed with the child, so take a ref from libudev as well */
-        sd_device_ref(parent->device);
-
-        return parent;
+        return udev_device_new(child->udev, parent);
 }
 
 /**
@@ -424,8 +389,7 @@ static struct udev_device *device_new_from_parent(struct udev_device *child)
  *
  * Returns: a new udev device, or #NULL, if it no parent exist.
  **/
-_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
-{
+_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) {
         assert_return_errno(udev_device, NULL, EINVAL);
 
         if (!udev_device->parent_set) {
@@ -458,8 +422,7 @@ _public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_dev
  *
  * Returns: a new udev device, or #NULL if no matching parent exists.
  **/
-_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
-{
+_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) {
         sd_device *parent;
         int r;
 
@@ -494,13 +457,26 @@ _public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struc
  *
  * Returns: the udev library context
  **/
-_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device)
-{
+_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device) {
         assert_return_errno(udev_device, NULL, EINVAL);
 
         return udev_device->udev;
 }
 
+static struct udev_device *udev_device_free(struct udev_device *udev_device) {
+        assert(udev_device);
+
+        sd_device_unref(udev_device->device);
+        udev_device_unref(udev_device->parent);
+
+        udev_list_cleanup(&udev_device->properties);
+        udev_list_cleanup(&udev_device->sysattrs);
+        udev_list_cleanup(&udev_device->tags);
+        udev_list_cleanup(&udev_device->devlinks);
+
+        return mfree(udev_device);
+}
+
 /**
  * udev_device_ref:
  * @udev_device: udev device
@@ -509,13 +485,6 @@ _public_ struct udev *udev_device_get_udev(struct udev_device *udev_device)
  *
  * Returns: the passed udev device
  **/
-_public_ struct udev_device *udev_device_ref(struct udev_device *udev_device)
-{
-        if (udev_device)
-                udev_device->refcount++;
-
-        return udev_device;
-}
 
 /**
  * udev_device_unref:
@@ -526,22 +495,7 @@ _public_ struct udev_device *udev_device_ref(struct udev_device *udev_device)
  *
  * Returns: #NULL
  **/
-_public_ struct udev_device *udev_device_unref(struct udev_device *udev_device)
-{
-        if (udev_device && (-- udev_device->refcount) == 0) {
-                sd_device_unref(udev_device->device);
-                udev_device_unref(udev_device->parent);
-
-                udev_list_cleanup(&udev_device->properties);
-                udev_list_cleanup(&udev_device->sysattrs);
-                udev_list_cleanup(&udev_device->tags);
-                udev_list_cleanup(&udev_device->devlinks);
-
-                free(udev_device);
-        }
-
-        return NULL;
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_device, udev_device, udev_device_free);
 
 /**
  * udev_device_get_devpath:
@@ -552,8 +506,7 @@ _public_ struct udev_device *udev_device_unref(struct udev_device *udev_device)
  *
  * Returns: the devpath of the udev device
  **/
-_public_ const char *udev_device_get_devpath(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_devpath(struct udev_device *udev_device) {
         const char *devpath;
         int r;
 
@@ -577,8 +530,7 @@ _public_ const char *udev_device_get_devpath(struct udev_device *udev_device)
  *
  * Returns: the sys path of the udev device
  **/
-_public_ const char *udev_device_get_syspath(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_syspath(struct udev_device *udev_device) {
         const char *syspath;
         int r;
 
@@ -601,8 +553,7 @@ _public_ const char *udev_device_get_syspath(struct udev_device *udev_device)
  *
  * Returns: the name string of the device
  **/
-_public_ const char *udev_device_get_sysname(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_sysname(struct udev_device *udev_device) {
         const char *sysname;
         int r;
 
@@ -625,8 +576,7 @@ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device)
  *
  * Returns: the trailing number string of the device name
  **/
-_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) {
         const char *sysnum;
         int r;
 
@@ -634,7 +584,8 @@ _public_ const char *udev_device_get_sysnum(struct udev_device *udev_device)
 
         r = sd_device_get_sysnum(udev_device->device, &sysnum);
         if (r < 0) {
-                errno = -r;
+                if (r != -ENOENT)
+                        errno = -r;
                 return NULL;
         }
 
@@ -650,8 +601,7 @@ _public_ const char *udev_device_get_sysnum(struct udev_device *udev_device)
  *
  * Returns: the device node file name of the udev device, or #NULL if no device node exists
  **/
-_public_ const char *udev_device_get_devnode(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_devnode(struct udev_device *udev_device) {
         const char *devnode;
         int r;
 
@@ -679,8 +629,7 @@ _public_ const char *udev_device_get_devnode(struct udev_device *udev_device)
  *
  * Returns: the first entry of the device node link list
  **/
-_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) {
         assert_return_errno(udev_device, NULL, EINVAL);
 
         if (device_get_devlinks_generation(udev_device->device) != udev_device->devlinks_generation ||
@@ -711,8 +660,7 @@ _public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev
  *
  * Returns: the first entry of the property list
  **/
-_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) {
         assert_return_errno(udev_device, NULL, EINVAL);
 
         if (device_get_properties_generation(udev_device->device) != udev_device->properties_generation ||
@@ -768,8 +716,7 @@ _public_ const char *udev_device_get_action(struct udev_device *udev_device) {
  *
  * Returns: the number of microseconds since the device was first seen.
  **/
-_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
-{
+_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) {
         usec_t ts;
         int r;
 
@@ -777,7 +724,7 @@ _public_ unsigned long long int udev_device_get_usec_since_initialized(struct ud
 
         r = sd_device_get_usec_since_initialized(udev_device->device, &ts);
         if (r < 0) {
-                errno = EINVAL;
+                errno = -r;
                 return 0;
         }
 
@@ -794,8 +741,7 @@ _public_ unsigned long long int udev_device_get_usec_since_initialized(struct ud
  *
  * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value.
  **/
-_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
-{
+_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
         const char *value;
         int r;
 
@@ -820,8 +766,7 @@ _public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_devi
  *
  * Returns: Negative error code on failure or 0 on success.
  **/
-_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value)
-{
+_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value) {
         int r;
 
         assert_return(udev_device, -EINVAL);
@@ -843,8 +788,7 @@ _public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, cons
  *
  * Returns: the first entry of the property list
  **/
-_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) {
         assert_return_errno(udev_device, NULL, EINVAL);
 
         if (!udev_device->sysattrs_read) {
@@ -874,8 +818,7 @@ _public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_
  *
  * Returns: 1 if the device is set up. 0 otherwise.
  **/
-_public_ int udev_device_get_is_initialized(struct udev_device *udev_device)
-{
+_public_ int udev_device_get_is_initialized(struct udev_device *udev_device) {
         int r, initialized;
 
         assert_return(udev_device, -EINVAL);
@@ -883,7 +826,6 @@ _public_ int udev_device_get_is_initialized(struct udev_device *udev_device)
         r = sd_device_get_is_initialized(udev_device->device, &initialized);
         if (r < 0) {
                 errno = -r;
-
                 return 0;
         }
 
@@ -901,8 +843,7 @@ _public_ int udev_device_get_is_initialized(struct udev_device *udev_device)
  *
  * Returns: the first entry of the tag list
  **/
-_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) {
         assert_return_errno(udev_device, NULL, EINVAL);
 
         if (device_get_tags_generation(udev_device->device) != udev_device->tags_generation ||
@@ -930,9 +871,8 @@ _public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_dev
  *
  * Returns: 1 if the tag is found. 0 otherwise.
  **/
-_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag)
-{
+_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) {
         assert_return(udev_device, 0);
 
-        return sd_device_has_tag(udev_device->device, tag);
+        return sd_device_has_tag(udev_device->device, tag) > 0;
 }
index e9f0f2e47ec4609cd29e020dda6b6534aee53a6c..41318d0a8db4f5efdb81dbea2d0b5501ab0927ac 100644 (file)
@@ -33,7 +33,7 @@
  */
 struct udev_enumerate {
         struct udev *udev;
-        int refcount;
+        unsigned n_ref;
         struct udev_list devices_list;
         bool devices_uptodate:1;
 
@@ -49,33 +49,45 @@ struct udev_enumerate {
  * Returns: an enumeration context.
  **/
 _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
-        _cleanup_free_ struct udev_enumerate *udev_enumerate = NULL;
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        struct udev_enumerate *udev_enumerate;
         int r;
 
-        udev_enumerate = new0(struct udev_enumerate, 1);
-        if (!udev_enumerate) {
-                errno = ENOMEM;
+        r = sd_device_enumerator_new(&e);
+        if (r < 0) {
+                errno = -r;
                 return NULL;
         }
 
-        r = sd_device_enumerator_new(&udev_enumerate->enumerator);
+        r = sd_device_enumerator_allow_uninitialized(e);
         if (r < 0) {
                 errno = -r;
                 return NULL;
         }
 
-        r = sd_device_enumerator_allow_uninitialized(udev_enumerate->enumerator);
-        if (r < 0) {
-                errno = -r;
+        udev_enumerate = new(struct udev_enumerate, 1);
+        if (!udev_enumerate) {
+                errno = ENOMEM;
                 return NULL;
         }
 
-        udev_enumerate->refcount = 1;
-        udev_enumerate->udev = udev;
+        *udev_enumerate = (struct udev_enumerate) {
+                .udev = udev,
+                .n_ref = 1,
+                .enumerator = TAKE_PTR(e),
+        };
 
         udev_list_init(udev, &udev_enumerate->devices_list, false);
 
-        return TAKE_PTR(udev_enumerate);
+        return udev_enumerate;
+}
+
+static struct udev_enumerate *udev_enumerate_free(struct udev_enumerate *udev_enumerate) {
+        assert(udev_enumerate);
+
+        udev_list_cleanup(&udev_enumerate->devices_list);
+        sd_device_enumerator_unref(udev_enumerate->enumerator);
+        return mfree(udev_enumerate);
 }
 
 /**
@@ -86,12 +98,6 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
  *
  * Returns: the passed enumeration context
  **/
-_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
-        if (udev_enumerate)
-                udev_enumerate->refcount++;
-
-        return udev_enumerate;
-}
 
 /**
  * udev_enumerate_unref:
@@ -102,15 +108,7 @@ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_e
  *
  * Returns: #NULL
  **/
-_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
-        if (udev_enumerate && (-- udev_enumerate->refcount) == 0) {
-                udev_list_cleanup(&udev_enumerate->devices_list);
-                sd_device_enumerator_unref(udev_enumerate->enumerator);
-                free(udev_enumerate);
-        }
-
-        return NULL;
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_enumerate, udev_enumerate, udev_enumerate_free);
 
 /**
  * udev_enumerate_get_udev:
index d13cc4dfb57dfeca00b23105d6a5d80fd935b8d4..1b478a6c4bdcef382dfdf5f88a41dd063bf0d9ff 100644 (file)
  * Opaque object representing the hardware database.
  */
 struct udev_hwdb {
-        struct udev *udev;
-        int refcount;
-
+        unsigned n_ref;
         sd_hwdb *hwdb;
-
         struct udev_list properties_list;
 };
 
 /**
  * udev_hwdb_new:
- * @udev: udev library context
+ * @udev: udev library context (unused)
  *
  * Create a hardware database context to query properties for devices.
  *
@@ -46,20 +43,30 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
                 return NULL;
         }
 
-        hwdb = new0(struct udev_hwdb, 1);
+        hwdb = new(struct udev_hwdb, 1);
         if (!hwdb) {
                 errno = ENOMEM;
                 return NULL;
         }
 
-        hwdb->refcount = 1;
-        hwdb->hwdb = TAKE_PTR(hwdb_internal);
+        *hwdb = (struct udev_hwdb) {
+                .n_ref = 1,
+                .hwdb = TAKE_PTR(hwdb_internal),
+        };
 
         udev_list_init(udev, &hwdb->properties_list, true);
 
         return hwdb;
 }
 
+static struct udev_hwdb *udev_hwdb_free(struct udev_hwdb *hwdb) {
+        assert(hwdb);
+
+        sd_hwdb_unref(hwdb->hwdb);
+        udev_list_cleanup(&hwdb->properties_list);
+        return mfree(hwdb);
+}
+
 /**
  * udev_hwdb_ref:
  * @hwdb: context
@@ -68,12 +75,6 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
  *
  * Returns: the passed enumeration context
  **/
-_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) {
-        if (!hwdb)
-                return NULL;
-        hwdb->refcount++;
-        return hwdb;
-}
 
 /**
  * udev_hwdb_unref:
@@ -84,16 +85,7 @@ _public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) {
  *
  * Returns: #NULL
  **/
-_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
-        if (!hwdb)
-                return NULL;
-        hwdb->refcount--;
-        if (hwdb->refcount > 0)
-                return NULL;
-        sd_hwdb_unref(hwdb->hwdb);
-        udev_list_cleanup(&hwdb->properties_list);
-        return mfree(hwdb);
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_hwdb, udev_hwdb, udev_hwdb_free);
 
 /**
  * udev_hwdb_get_properties_list_entry:
@@ -112,10 +104,8 @@ _public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev
         const char *key, *value;
         struct udev_list_entry *e;
 
-        if (!hwdb || !modalias) {
-                errno = EINVAL;
-                return NULL;
-        }
+        assert_return_errno(hwdb, NULL, EINVAL);
+        assert_return_errno(modalias, NULL, EINVAL);
 
         udev_list_cleanup(&hwdb->properties_list);
 
index f0b5081392c9014229b1fa07ebce27d7ad20a71b..ea443083510acdb6e5d45c7bebc362ddbbae9bec 100644 (file)
 #include "libudev.h"
 
 #include "alloc-util.h"
+#include "device-private.h"
+#include "device-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
-#include "libudev-private.h"
+#include "hashmap.h"
 #include "libudev-device-internal.h"
+#include "libudev-private.h"
 #include "missing.h"
 #include "mount-util.h"
+#include "set.h"
 #include "socket-util.h"
 #include "string-util.h"
+#include "strv.h"
 
 /**
  * SECTION:libudev-monitor
  */
 struct udev_monitor {
         struct udev *udev;
-        int refcount;
+        unsigned n_ref;
         int sock;
         union sockaddr_union snl;
         union sockaddr_union snl_trusted_sender;
         union sockaddr_union snl_destination;
         socklen_t addrlen;
-        struct udev_list filter_subsystem_list;
-        struct udev_list filter_tag_list;
+        Hashmap *subsystem_filter;
+        Set *tag_filter;
         bool bound;
 };
 
@@ -63,98 +68,47 @@ struct udev_monitor_netlink_header {
          * magic to protect against daemon <-> library message format mismatch
          * used in the kernel from socket filter rules; needs to be stored in network order
          */
-        unsigned int magic;
+        unsigned magic;
         /* total length of header structure known to the sender */
-        unsigned int header_size;
+        unsigned header_size;
         /* properties string buffer */
-        unsigned int properties_off;
-        unsigned int properties_len;
+        unsigned properties_off;
+        unsigned properties_len;
         /*
          * hashes of primary device properties strings, to let libudev subscribers
          * use in-kernel socket filters; values need to be stored in network order
          */
-        unsigned int filter_subsystem_hash;
-        unsigned int filter_devtype_hash;
-        unsigned int filter_tag_bloom_hi;
-        unsigned int filter_tag_bloom_lo;
+        unsigned filter_subsystem_hash;
+        unsigned filter_devtype_hash;
+        unsigned filter_tag_bloom_hi;
+        unsigned filter_tag_bloom_lo;
 };
 
-static struct udev_monitor *udev_monitor_new(struct udev *udev) {
-        struct udev_monitor *udev_monitor;
-
-        udev_monitor = new0(struct udev_monitor, 1);
-        if (udev_monitor == NULL) {
-                errno = ENOMEM;
-                return NULL;
-        }
-        udev_monitor->refcount = 1;
-        udev_monitor->udev = udev;
-        udev_list_init(udev, &udev_monitor->filter_subsystem_list, false);
-        udev_list_init(udev, &udev_monitor->filter_tag_list, true);
-        return udev_monitor;
-}
-
-/* we consider udev running when /dev is on devtmpfs */
-static bool udev_has_devtmpfs(struct udev *udev) {
-
-        _cleanup_fclose_ FILE *f = NULL;
-        char line[LINE_MAX], *e;
-        int mount_id, r;
-
-        r = path_get_mnt_id("/dev", &mount_id);
-        if (r < 0) {
-                if (r != -EOPNOTSUPP)
-                        log_debug_errno(r, "name_to_handle_at on /dev: %m");
-
-                return false;
-        }
-
-        f = fopen("/proc/self/mountinfo", "re");
-        if (!f)
-                return false;
-
-        FOREACH_LINE(line, f, return false) {
-                int mid;
-
-                if (sscanf(line, "%i", &mid) != 1)
-                        continue;
-
-                if (mid != mount_id)
-                        continue;
-
-                e = strstr(line, " - ");
-                if (!e)
-                        continue;
-
-                /* accept any name that starts with the currently expected type */
-                if (startswith(e + 3, "devtmpfs"))
-                        return true;
-        }
-
-        return false;
-}
-
-static void monitor_set_nl_address(struct udev_monitor *udev_monitor) {
+static int udev_monitor_set_nl_address(struct udev_monitor *udev_monitor) {
         union sockaddr_union snl;
         socklen_t addrlen;
-        int r;
 
         assert(udev_monitor);
 
-        /* get the address the kernel has assigned us
-         * it is usually, but not necessarily the pid
-         */
+        /* Get the address the kernel has assigned us.
+         * It is usually, but not necessarily the pid. */
         addrlen = sizeof(struct sockaddr_nl);
-        r = getsockname(udev_monitor->sock, &snl.sa, &addrlen);
-        if (r >= 0)
-                udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
+        if (getsockname(udev_monitor->sock, &snl.sa, &addrlen) < 0)
+                return -errno;
+
+        udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
+        return 0;
 }
 
 struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) {
-        struct udev_monitor *udev_monitor;
-        unsigned int group;
+        _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor = NULL;
+        _cleanup_close_ int sock = -1;
+        unsigned group;
+        int r;
 
-        if (name == NULL)
+        assert_return_errno(!name || STR_IN_SET(name, "udev", "kernel"), NULL, EINVAL);
+
+        if (!name)
                 group = UDEV_MONITOR_NONE;
         else if (streq(name, "udev")) {
                 /*
@@ -169,42 +123,52 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
                  * We do not set a netlink multicast group here, so the socket
                  * will not receive any messages.
                  */
-                if (access("/run/udev/control", F_OK) < 0 && !udev_has_devtmpfs(udev)) {
-                        log_debug("the udev service seems not to be active, disable the monitor");
+                if (access("/run/udev/control", F_OK) < 0 && dev_is_devtmpfs() <= 0) {
+                        log_debug("The udev service seems not to be active, disabling the monitor");
                         group = UDEV_MONITOR_NONE;
                 } else
                         group = UDEV_MONITOR_UDEV;
-        } else if (streq(name, "kernel"))
+        } else {
+                assert(streq(name, "kernel"));
                 group = UDEV_MONITOR_KERNEL;
-        else {
-                errno = EINVAL;
-                return NULL;
         }
 
-        udev_monitor = udev_monitor_new(udev);
-        if (udev_monitor == NULL)
-                return NULL;
-
         if (fd < 0) {
-                udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
-                if (udev_monitor->sock < 0) {
-                        log_debug_errno(errno, "error getting socket: %m");
-                        return mfree(udev_monitor);
+                sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
+                if (sock < 0) {
+                        log_debug_errno(errno, "Failed to create socket: %m");
+                        return NULL;
                 }
-        } else {
-                udev_monitor->bound = true;
-                udev_monitor->sock = fd;
-                monitor_set_nl_address(udev_monitor);
         }
 
-        udev_monitor->snl.nl.nl_family = AF_NETLINK;
-        udev_monitor->snl.nl.nl_groups = group;
+        udev_monitor = new(struct udev_monitor, 1);
+        if (!udev_monitor) {
+                errno = ENOMEM;
+                return NULL;
+        }
+
+        *udev_monitor = (struct udev_monitor) {
+                .udev = udev,
+                .n_ref = 1,
+                .sock = fd >= 0 ? fd : TAKE_FD(sock),
+                .bound = fd >= 0,
+                .snl.nl.nl_family = AF_NETLINK,
+                .snl.nl.nl_groups = group,
+
+                /* default destination for sending */
+                .snl_destination.nl.nl_family = AF_NETLINK,
+                .snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV,
+        };
 
-        /* default destination for sending */
-        udev_monitor->snl_destination.nl.nl_family = AF_NETLINK;
-        udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV;
+        if (fd >= 0) {
+                r = udev_monitor_set_nl_address(udev_monitor);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to set netlink address: %m");
+                        return NULL;
+                }
+        }
 
-        return udev_monitor;
+        return TAKE_PTR(udev_monitor);
 }
 
 /**
@@ -233,27 +197,23 @@ _public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, c
         return udev_monitor_new_from_netlink_fd(udev, name, -1);
 }
 
-static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
-                            unsigned short code, unsigned int data)
-{
-        struct sock_filter *ins = &inss[*i];
-
-        ins->code = code;
-        ins->k = data;
-        (*i)++;
+static void bpf_stmt(struct sock_filter *ins, unsigned *i,
+                     unsigned short code, unsigned data) {
+        ins[(*i)++] = (struct sock_filter) {
+                .code = code,
+                .k = data,
+        };
 }
 
-static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
-                           unsigned short code, unsigned int data,
-                           unsigned short jt, unsigned short jf)
-{
-        struct sock_filter *ins = &inss[*i];
-
-        ins->code = code;
-        ins->jt = jt;
-        ins->jf = jf;
-        ins->k = data;
-        (*i)++;
+static void bpf_jmp(struct sock_filter *ins, unsigned *i,
+                    unsigned short code, unsigned data,
+                    unsigned short jt, unsigned short jf) {
+        ins[(*i)++] = (struct sock_filter) {
+                .code = code,
+                .jt = jt,
+                .jf = jf,
+                .k = data,
+        };
 }
 
 /**
@@ -265,20 +225,18 @@ static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
-{
-        struct sock_filter ins[512];
+_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) {
+        struct sock_filter ins[512] = {};
         struct sock_fprog filter;
-        unsigned int i;
-        struct udev_list_entry *list_entry;
-        int err;
+        const char *subsystem, *devtype, *tag;
+        unsigned i = 0;
+        Iterator it;
 
-        if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL &&
-            udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
-                return 0;
+        assert_return(udev_monitor, -EINVAL);
 
-        memzero(ins, sizeof(ins));
-        i = 0;
+        if (hashmap_isempty(udev_monitor->subsystem_filter) &&
+            set_isempty(udev_monitor->tag_filter))
+                return 0;
 
         /* load magic in A */
         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
@@ -287,17 +245,12 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
         /* wrong magic, pass packet */
         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
 
-        if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) {
-                int tag_matches;
-
-                /* count tag matches, to calculate end of tag match block */
-                tag_matches = 0;
-                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))
-                        tag_matches++;
+        if (!set_isempty(udev_monitor->tag_filter)) {
+                int tag_matches = set_size(udev_monitor->tag_filter);
 
                 /* add all tags matches */
-                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
-                        uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry));
+                SET_FOREACH(tag, udev_monitor->tag_filter, it) {
+                        uint64_t tag_bloom_bits = util_string_bloom64(tag);
                         uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
                         uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
 
@@ -322,23 +275,23 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
         }
 
         /* add all subsystem matches */
-        if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) {
-                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
-                        unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry));
+        if (!hashmap_isempty(udev_monitor->subsystem_filter)) {
+                HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, it) {
+                        uint32_t hash = util_string_hash32(subsystem);
 
                         /* load device subsystem value in A */
                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash));
-                        if (udev_list_entry_get_value(list_entry) == NULL) {
+                        if (!devtype) {
                                 /* jump if subsystem does not match */
                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
                         } else {
+                                hash = util_string_hash32(devtype);
+
                                 /* jump if subsystem does not match */
                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
-
                                 /* load device devtype value in A */
                                 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash));
                                 /* jump if value does not match */
-                                hash = util_string_hash32(udev_list_entry_get_value(list_entry));
                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
                         }
 
@@ -357,15 +310,20 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
 
         /* install filter */
-        memzero(&filter, sizeof(filter));
-        filter.len = i;
-        filter.filter = ins;
-        err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
-        return err < 0 ? -errno : 0;
+        filter = (struct sock_fprog) {
+                .len = i,
+                .filter = ins,
+        };
+        if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
+                return -errno;
+
+        return 0;
 }
 
-int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
-{
+int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) {
+        assert_return(udev_monitor, -EINVAL);
+        assert_return(sender, -EINVAL);
+
         udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
         return 0;
 }
@@ -378,29 +336,30 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
-{
-        int err = 0;
+_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) {
         const int on = 1;
+        int r;
 
-        udev_monitor_filter_update(udev_monitor);
+        assert_return(udev_monitor, -EINVAL);
+
+        r = udev_monitor_filter_update(udev_monitor);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to update filter: %m");
 
         if (!udev_monitor->bound) {
-                err = bind(udev_monitor->sock,
-                           &udev_monitor->snl.sa, sizeof(struct sockaddr_nl));
-                if (err == 0)
-                        udev_monitor->bound = true;
+                if (bind(udev_monitor->sock, &udev_monitor->snl.sa, sizeof(struct sockaddr_nl)) < 0)
+                        return log_debug_errno(errno, "Failed to bind udev monitor socket to event source: %m");
+
+                udev_monitor->bound = true;
         }
 
-        if (err >= 0)
-                monitor_set_nl_address(udev_monitor);
-        else
-                return log_debug_errno(errno, "bind failed: %m");
+        r = udev_monitor_set_nl_address(udev_monitor);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to set address: %m");
 
         /* enable receiving of sender credentials */
-        err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
-        if (err < 0)
-                log_debug_errno(errno, "setting SO_PASSCRED failed: %m");
+        if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0)
+                return log_debug_errno(errno, "Failed to set socket option SO_PASSCRED: %m");
 
         return 0;
 }
@@ -415,23 +374,29 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
  *
  * Returns: 0 on success, otherwise -1 on error.
  */
-_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
-{
-        if (udev_monitor == NULL)
-                return -EINVAL;
+_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) {
+        assert_return(udev_monitor, -EINVAL);
+
         if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0)
                 return -errno;
 
         return 0;
 }
 
-int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
-{
-        int err;
+int udev_monitor_disconnect(struct udev_monitor *udev_monitor) {
+        assert(udev_monitor);
+
+        udev_monitor->sock = safe_close(udev_monitor->sock);
+        return 0;
+}
+
+static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) {
+        assert(udev_monitor);
 
-        err = close(udev_monitor->sock);
-        udev_monitor->sock = -1;
-        return err < 0 ? -errno : 0;
+        udev_monitor_disconnect(udev_monitor);
+        hashmap_free_free_free(udev_monitor->subsystem_filter);
+        set_free_free(udev_monitor->tag_filter);
+        return mfree(udev_monitor);
 }
 
 /**
@@ -442,13 +407,6 @@ int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
  *
  * Returns: the passed udev monitor
  **/
-_public_ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
-{
-        if (udev_monitor == NULL)
-                return NULL;
-        udev_monitor->refcount++;
-        return udev_monitor;
-}
 
 /**
  * udev_monitor_unref:
@@ -460,19 +418,7 @@ _public_ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor
  *
  * Returns: #NULL
  **/
-_public_ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor)
-{
-        if (udev_monitor == NULL)
-                return NULL;
-        udev_monitor->refcount--;
-        if (udev_monitor->refcount > 0)
-                return NULL;
-        if (udev_monitor->sock >= 0)
-                close(udev_monitor->sock);
-        udev_list_cleanup(&udev_monitor->filter_subsystem_list);
-        udev_list_cleanup(&udev_monitor->filter_tag_list);
-        return mfree(udev_monitor);
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_monitor_free);
 
 /**
  * udev_monitor_get_udev:
@@ -482,10 +428,9 @@ _public_ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monit
  *
  * Returns: the udev library context
  **/
-_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
-{
-        if (udev_monitor == NULL)
-                return NULL;
+_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
+        assert_return(udev_monitor, NULL);
+
         return udev_monitor->udev;
 }
 
@@ -497,230 +442,228 @@ _public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
  *
  * Returns: the socket file descriptor
  **/
-_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
-{
-        if (udev_monitor == NULL)
-                return -EINVAL;
+_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) {
+        assert_return(udev_monitor, -EINVAL);
+
         return udev_monitor->sock;
 }
 
-static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
-{
-        struct udev_list_entry *list_entry;
+static int passes_filter(struct udev_monitor *udev_monitor, sd_device *device) {
+        const char *tag, *subsystem, *devtype, *s, *d = NULL;
+        Iterator i;
+        int r;
+
+        assert_return(udev_monitor, -EINVAL);
+        assert_return(device, -EINVAL);
 
-        if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
+        if (hashmap_isempty(udev_monitor->subsystem_filter))
                 goto tag;
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
-                const char *subsys = udev_list_entry_get_name(list_entry);
-                const char *dsubsys = udev_device_get_subsystem(udev_device);
-                const char *devtype;
-                const char *ddevtype;
 
-                if (!streq(dsubsys, subsys))
+        r = sd_device_get_subsystem(device, &s);
+        if (r < 0)
+                return r;
+
+        r = sd_device_get_devtype(device, &d);
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, i) {
+                if (!streq(s, subsystem))
                         continue;
 
-                devtype = udev_list_entry_get_value(list_entry);
-                if (devtype == NULL)
+                if (!devtype)
                         goto tag;
-                ddevtype = udev_device_get_devtype(udev_device);
-                if (ddevtype == NULL)
+
+                if (!d)
                         continue;
-                if (streq(ddevtype, devtype))
+
+                if (streq(d, devtype))
                         goto tag;
         }
+
         return 0;
 
 tag:
-        if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
+        if (set_isempty(udev_monitor->tag_filter))
                 return 1;
-        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
-                const char *tag = udev_list_entry_get_name(list_entry);
 
-                if (udev_device_has_tag(udev_device, tag))
+        SET_FOREACH(tag, udev_monitor->tag_filter, i)
+                if (sd_device_has_tag(device, tag) > 0)
                         return 1;
-        }
+
         return 0;
 }
 
-/**
- * udev_monitor_receive_device:
- * @udev_monitor: udev monitor
- *
- * Receive data from the udev monitor socket, allocate a new udev
- * device, fill in the received data, and return the device.
- *
- * Only socket connections with uid=0 are accepted.
- *
- * The monitor socket is by default set to NONBLOCK. A variant of poll() on
- * the file descriptor returned by udev_monitor_get_fd() should to be used to
- * wake up when new devices arrive, or alternatively the file descriptor
- * switched into blocking mode.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev device.
- *
- * Returns: a new udev device, or #NULL, in case of an error
- **/
-_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
-{
-        struct udev_device *udev_device;
-        struct msghdr smsg;
-        struct iovec iov;
-        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
-        struct cmsghdr *cmsg;
-        union sockaddr_union snl;
-        struct ucred *cred;
+static int udev_monitor_receive_device_one(struct udev_monitor *udev_monitor, sd_device **ret) {
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         union {
                 struct udev_monitor_netlink_header nlh;
                 char raw[8192];
         } buf;
-        ssize_t buflen;
-        ssize_t bufpos;
+        struct iovec iov = {
+                .iov_base = &buf,
+                .iov_len = sizeof(buf)
+        };
+        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+        union sockaddr_union snl;
+        struct msghdr smsg = {
+                .msg_iov = &iov,
+                .msg_iovlen = 1,
+                .msg_control = cred_msg,
+                .msg_controllen = sizeof(cred_msg),
+                .msg_name = &snl,
+                .msg_namelen = sizeof(snl),
+        };
+        struct cmsghdr *cmsg;
+        struct ucred *cred;
+        ssize_t buflen, bufpos;
         bool is_initialized = false;
+        int r;
 
-retry:
-        if (udev_monitor == NULL) {
-                errno = EINVAL;
-                return NULL;
-        }
-        iov.iov_base = &buf;
-        iov.iov_len = sizeof(buf);
-        memzero(&smsg, sizeof(struct msghdr));
-        smsg.msg_iov = &iov;
-        smsg.msg_iovlen = 1;
-        smsg.msg_control = cred_msg;
-        smsg.msg_controllen = sizeof(cred_msg);
-        smsg.msg_name = &snl;
-        smsg.msg_namelen = sizeof(snl);
+        assert(ret);
 
         buflen = recvmsg(udev_monitor->sock, &smsg, 0);
         if (buflen < 0) {
                 if (errno != EINTR)
-                        log_debug("unable to receive message");
-                return NULL;
+                        log_debug_errno(errno, "Failed to receive message: %m");
+                return -errno;
         }
 
-        if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) {
-                log_debug("invalid message length");
-                errno = EINVAL;
-                return NULL;
-        }
+        if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC))
+                return log_debug_errno(EINVAL, "Invalid message length.");
 
-        if (snl.nl.nl_groups == 0) {
+        if (snl.nl.nl_groups == UDEV_MONITOR_NONE) {
                 /* unicast message, check if we trust the sender */
                 if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 ||
-                    snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) {
-                        log_debug("unicast netlink message ignored");
-                        errno = EAGAIN;
-                        return NULL;
-                }
+                    snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid)
+                        return log_debug_errno(EAGAIN, "Unicast netlink message ignored.");
+
         } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
-                if (snl.nl.nl_pid > 0) {
-                        log_debug("multicast kernel netlink message from PID %"PRIu32" ignored",
-                                  snl.nl.nl_pid);
-                        errno = EAGAIN;
-                        return NULL;
-                }
+                if (snl.nl.nl_pid > 0)
+                        return log_debug_errno(EAGAIN, "Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
         }
 
         cmsg = CMSG_FIRSTHDR(&smsg);
-        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-                log_debug("no sender credentials received, message ignored");
-                errno = EAGAIN;
-                return NULL;
-        }
+        if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
+                return log_debug_errno(EAGAIN, "No sender credentials received, message ignored.");
 
-        cred = (struct ucred *)CMSG_DATA(cmsg);
-        if (cred->uid != 0) {
-                log_debug("sender uid="UID_FMT", message ignored", cred->uid);
-                errno = EAGAIN;
-                return NULL;
-        }
+        cred = (struct ucred*) CMSG_DATA(cmsg);
+        if (cred->uid != 0)
+                return log_debug_errno(EAGAIN, "Sender uid="UID_FMT", message ignored.", cred->uid);
 
-        if (memcmp(buf.raw, "libudev", 8) == 0) {
+        if (streq(buf.raw, "libudev")) {
                 /* udev message needs proper version magic */
-                if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) {
-                        log_debug("unrecognized message signature (%x != %x)",
-                                 buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
-                        errno = EAGAIN;
-                        return NULL;
-                }
-                if (buf.nlh.properties_off+32 > (size_t)buflen) {
-                        log_debug("message smaller than expected (%u > %zd)",
-                                  buf.nlh.properties_off+32, buflen);
-                        errno = EAGAIN;
-                        return NULL;
-                }
+                if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC))
+                        return log_debug_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(EAGAIN, "Invalid message length (%u > %zd)",
+                                               buf.nlh.properties_off+32, buflen);
 
                 bufpos = buf.nlh.properties_off;
 
                 /* devices received from udev are always initialized */
                 is_initialized = true;
+
         } else {
                 /* kernel message with header */
                 bufpos = strlen(buf.raw) + 1;
-                if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
-                        log_debug("invalid message length");
-                        errno = EAGAIN;
-                        return NULL;
-                }
+                if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen)
+                        return log_debug_errno(EAGAIN, "Invalid message length");
 
                 /* check message header */
-                if (strstr(buf.raw, "@/") == NULL) {
-                        log_debug("unrecognized message header");
-                        errno = EAGAIN;
-                        return NULL;
-                }
+                if (!strstr(buf.raw, "@/"))
+                        return log_debug_errno(EAGAIN, "Invalid message header");
         }
 
-        udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
-        if (!udev_device) {
-                log_debug_errno(errno, "could not create device: %m");
-                return NULL;
-        }
+        r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to create device: %m");
 
         if (is_initialized)
-                udev_device_set_is_initialized(udev_device);
+                device_set_is_initialized(device);
 
         /* skip device, if it does not pass the current filter */
-        if (!passes_filter(udev_monitor, udev_device)) {
-                struct pollfd pfd[1];
-                int rc;
+        if (passes_filter(udev_monitor, device) <= 0)
+                return 0;
 
-                udev_device_unref(udev_device);
+        *ret = TAKE_PTR(device);
+        return 1;
+}
 
-                /* if something is queued, get next device */
-                pfd[0].fd = udev_monitor->sock;
-                pfd[0].events = POLLIN;
-                rc = poll(pfd, 1, 0);
-                if (rc > 0)
-                        goto retry;
+int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) {
+        struct pollfd pfd = {
+                .fd = udev_monitor->sock,
+                .events = POLLIN,
+        };
+        int r;
 
-                errno = EAGAIN;
-                return NULL;
-        }
+        assert(udev_monitor);
+        assert(ret);
 
-        return udev_device;
+        for (;;) {
+                /* r == 0 means a device is received but it does not pass the current filter. */
+                r = udev_monitor_receive_device_one(udev_monitor, ret);
+                if (r != 0)
+                        return r;
+
+                for (;;) {
+                        /* wait next message */
+                        r = poll(&pfd, 1, 0);
+                        if (r < 0) {
+                                if (IN_SET(errno, EINTR, EAGAIN))
+                                        continue;
+
+                                return -errno;
+                        } else if (r == 0)
+                                return -EAGAIN;
+
+                        /* receive next message */
+                        break;
+                }
+        }
 }
 
-int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) {
-        _cleanup_(udev_device_unrefp) struct udev_device *udev_device = NULL;
+/**
+ * udev_monitor_receive_device:
+ * @udev_monitor: udev monitor
+ *
+ * Receive data from the udev monitor socket, allocate a new udev
+ * device, fill in the received data, and return the device.
+ *
+ * Only socket connections with uid=0 are accepted.
+ *
+ * The monitor socket is by default set to NONBLOCK. A variant of poll() on
+ * the file descriptor returned by udev_monitor_get_fd() should to be used to
+ * wake up when new devices arrive, or alternatively the file descriptor
+ * switched into blocking mode.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev device.
+ *
+ * Returns: a new udev device, or #NULL, in case of an error
+ **/
+_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) {
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+        int r;
 
-        assert(ret);
+        assert_return(udev_monitor, NULL);
 
-        udev_device = udev_monitor_receive_device(udev_monitor);
-        if (!udev_device)
-                return -errno;
+        r = udev_monitor_receive_sd_device(udev_monitor, &device);
+        if (r < 0) {
+                errno = -r;
+                return NULL;
+        }
 
-        *ret = sd_device_ref(udev_device->device);
-        return 0;
+        return udev_device_new(udev_monitor->udev, device);
 }
 
-int udev_monitor_send_device(struct udev_monitor *udev_monitor,
-                             struct udev_monitor *destination, struct udev_device *udev_device)
-{
-        const char *buf, *val;
-        ssize_t blen, count;
+static int udev_monitor_send_sd_device(
+                struct udev_monitor *udev_monitor,
+                struct udev_monitor *destination,
+                sd_device *device) {
+
         struct udev_monitor_netlink_header nlh = {
                 .prefix = "libudev",
                 .magic = htobe32(UDEV_MONITOR_MAGIC),
@@ -733,27 +676,37 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
                 .msg_iov = iov,
                 .msg_iovlen = 2,
         };
-        struct udev_list_entry *list_entry;
         uint64_t tag_bloom_bits;
+        const char *buf, *val;
+        ssize_t count;
+        size_t blen;
+        int r;
 
-        blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
+        assert(udev_monitor);
+        assert(device);
+
+        r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get device properties: %m");
         if (blen < 32) {
-                log_debug("device buffer is too small to contain a valid device");
+                log_debug("Device buffer is too small to contain a valid device");
                 return -EINVAL;
         }
 
         /* fill in versioned header */
-        val = udev_device_get_subsystem(udev_device);
+        r = sd_device_get_subsystem(device, &val);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to get device subsystem: %m");
         nlh.filter_subsystem_hash = htobe32(util_string_hash32(val));
 
-        val = udev_device_get_devtype(udev_device);
-        if (val != NULL)
+        if (sd_device_get_devtype(device, &val) >= 0 && val)
                 nlh.filter_devtype_hash = htobe32(util_string_hash32(val));
 
         /* add tag bloom filter */
         tag_bloom_bits = 0;
-        udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
-                tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry));
+        FOREACH_DEVICE_TAG(device, val)
+                tag_bloom_bits |= util_string_bloom64(val);
+
         if (tag_bloom_bits > 0) {
                 nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32);
                 nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff);
@@ -762,8 +715,10 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
         /* add properties list */
         nlh.properties_off = iov[0].iov_len;
         nlh.properties_len = blen;
-        iov[1].iov_base = (char *)buf;
-        iov[1].iov_len = blen;
+        iov[1] = (struct iovec) {
+                .iov_base = (char*) buf,
+                .iov_len = blen,
+        };
 
         /*
          * Use custom address for target, or the default one.
@@ -771,24 +726,30 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
          * If we send to a multicast group, we will get
          * ECONNREFUSED, which is expected.
          */
-        if (destination)
-                smsg.msg_name = &destination->snl;
-        else
-                smsg.msg_name = &udev_monitor->snl_destination;
+        smsg.msg_name = destination ? &destination->snl : &udev_monitor->snl_destination;
         smsg.msg_namelen = sizeof(struct sockaddr_nl);
         count = sendmsg(udev_monitor->sock, &smsg, 0);
         if (count < 0) {
                 if (!destination && errno == ECONNREFUSED) {
-                        log_debug("passed device to netlink monitor %p", udev_monitor);
+                        log_debug("Passed device to netlink monitor %p", udev_monitor);
                         return 0;
                 } else
-                        return -errno;
+                        return log_debug_errno(errno, "Failed to send device to netlink monitor %p", udev_monitor);
         }
 
-        log_debug("passed %zi byte device to netlink monitor %p", count, udev_monitor);
+        log_debug("Passed %zi byte device to netlink monitor %p", count, udev_monitor);
         return count;
 }
 
+int udev_monitor_send_device(
+                struct udev_monitor *udev_monitor,
+                struct udev_monitor *destination,
+                struct udev_device *udev_device) {
+        assert(udev_device);
+
+        return udev_monitor_send_sd_device(udev_monitor, destination, udev_device->device);
+}
+
 /**
  * udev_monitor_filter_add_match_subsystem_devtype:
  * @udev_monitor: the monitor
@@ -802,14 +763,32 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
-{
-        if (udev_monitor == NULL)
-                return -EINVAL;
-        if (subsystem == NULL)
-                return -EINVAL;
-        if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL)
+_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) {
+        _cleanup_free_ char *s = NULL, *d = NULL;
+        int r;
+
+        assert_return(udev_monitor, -EINVAL);
+        assert_return(subsystem, -EINVAL);
+
+        s = strdup(subsystem);
+        if (!s)
                 return -ENOMEM;
+
+        if (devtype) {
+                d = strdup(devtype);
+                if (!d)
+                        return -ENOMEM;
+        }
+
+        r = hashmap_ensure_allocated(&udev_monitor->subsystem_filter, NULL);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(udev_monitor->subsystem_filter, s, d);
+        if (r < 0)
+                return r;
+
+        s = d = NULL;
         return 0;
 }
 
@@ -825,14 +804,28 @@ _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
-{
-        if (udev_monitor == NULL)
-                return -EINVAL;
-        if (tag == NULL)
-                return -EINVAL;
-        if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL)
+_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) {
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        assert_return(udev_monitor, -EINVAL);
+        assert_return(tag, -EINVAL);
+
+        t = strdup(tag);
+        if (!t)
                 return -ENOMEM;
+
+        r = set_ensure_allocated(&udev_monitor->tag_filter, &string_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = set_put(udev_monitor->tag_filter, t);
+        if (r == -EEXIST)
+                return 0;
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(t);
         return 0;
 }
 
@@ -844,11 +837,14 @@ _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor
  *
  * Returns: 0 on success, otherwise a negative error value.
  */
-_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
-{
+_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) {
         static const struct sock_fprog filter = { 0, NULL };
 
-        udev_list_cleanup(&udev_monitor->filter_subsystem_list);
+        assert_return(udev_monitor, -EINVAL);
+
+        udev_monitor->subsystem_filter = hashmap_free_free_free(udev_monitor->subsystem_filter);
+        udev_monitor->tag_filter = set_free_free(udev_monitor->tag_filter);
+
         if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
                 return -errno;
 
index 60968b9a2e81cca65bb69b66327ea83faa4d407e..9b1bf826097b707d11e6c865f6f4ab88b7f68990 100644 (file)
@@ -16,9 +16,6 @@
 #define READ_END  0
 #define WRITE_END 1
 
-/* libudev.c */
-int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]);
-
 /* libudev-device.c */
 struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen);
 struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action);
@@ -40,7 +37,6 @@ void udev_device_set_is_initialized(struct udev_device *udev_device);
 int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
 void udev_device_remove_tag(struct udev_device *udev_device, const char *tag);
 void udev_device_cleanup_tags_list(struct udev_device *udev_device);
-usec_t udev_device_get_usec_initialized(struct udev_device *udev_device);
 void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *old_device);
 int udev_device_get_devlink_priority(struct udev_device *udev_device);
 int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
@@ -48,11 +44,8 @@ int udev_device_get_watch_handle(struct udev_device *udev_device);
 int udev_device_set_watch_handle(struct udev_device *udev_device, int handle);
 int udev_device_get_ifindex(struct udev_device *udev_device);
 void udev_device_set_info_loaded(struct udev_device *device);
-bool udev_device_get_db_persist(struct udev_device *udev_device);
 void udev_device_set_db_persist(struct udev_device *udev_device);
 void udev_device_read_db(struct udev_device *udev_device);
-
-/* libudev-device-private.c */
 int udev_device_update_db(struct udev_device *udev_device);
 int udev_device_delete_db(struct udev_device *udev_device);
 int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add);
@@ -101,19 +94,6 @@ void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num);
              entry != NULL; \
              entry = tmp, tmp = udev_list_entry_get_next(tmp))
 
-/* libudev-queue.c */
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev);
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum);
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size);
-ssize_t udev_queue_skip_devpath(FILE *queue_file);
-
-/* libudev-queue-private.c */
-struct udev_queue_export *udev_queue_export_new(struct udev *udev);
-struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export);
-void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export);
-int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-
 /* libudev-util.c */
 #define UTIL_PATH_SIZE                      1024
 #define UTIL_NAME_SIZE                       512
index c45abfd520a31dc7a414eea4e7b18c224fc61dbd..832f3b3da5be0a8444dc7cf34469c0b90d1c1236 100644 (file)
@@ -28,7 +28,7 @@
  */
 struct udev_queue {
         struct udev *udev;
-        int refcount;
+        unsigned n_ref;
         int fd;
 };
 
@@ -41,22 +41,31 @@ struct udev_queue {
  *
  * Returns: the udev queue context, or #NULL on error.
  **/
-_public_ struct udev_queue *udev_queue_new(struct udev *udev)
-{
+_public_ struct udev_queue *udev_queue_new(struct udev *udev) {
         struct udev_queue *udev_queue;
 
-        udev_queue = new0(struct udev_queue, 1);
+        udev_queue = new(struct udev_queue, 1);
         if (udev_queue == NULL) {
                 errno = ENOMEM;
                 return NULL;
         }
 
-        udev_queue->refcount = 1;
-        udev_queue->udev = udev;
-        udev_queue->fd = -1;
+        *udev_queue = (struct udev_queue) {
+                .udev = udev,
+                .n_ref = 1,
+                .fd = -1,
+        };
+
         return udev_queue;
 }
 
+static struct udev_queue *udev_queue_free(struct udev_queue *udev_queue) {
+        assert(udev_queue);
+
+        safe_close(udev_queue->fd);
+        return mfree(udev_queue);
+}
+
 /**
  * udev_queue_ref:
  * @udev_queue: udev queue context
@@ -65,14 +74,6 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
  *
  * Returns: the same udev queue context.
  **/
-_public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
-{
-        if (udev_queue == NULL)
-                return NULL;
-
-        udev_queue->refcount++;
-        return udev_queue;
-}
 
 /**
  * udev_queue_unref:
@@ -83,19 +84,7 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
  *
  * Returns: #NULL
  **/
-_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
-{
-        if (udev_queue == NULL)
-                return NULL;
-
-        udev_queue->refcount--;
-        if (udev_queue->refcount > 0)
-                return NULL;
-
-        safe_close(udev_queue->fd);
-
-        return mfree(udev_queue);
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_queue, udev_queue, udev_queue_free);
 
 /**
  * udev_queue_get_udev:
@@ -105,12 +94,9 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
  *
  * Returns: the udev library context.
  **/
-_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
-{
-        if (udev_queue == NULL) {
-                errno = EINVAL;
-                return NULL;
-        }
+_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) {
+        assert_return_errno(udev_queue, NULL, EINVAL);
+
         return udev_queue->udev;
 }
 
@@ -122,8 +108,7 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
  *
  * Returns: 0.
  **/
-_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
-{
+_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) {
         return 0;
 }
 
@@ -135,8 +120,7 @@ _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *
  *
  * Returns: 0.
  **/
-_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
-{
+_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) {
         return 0;
 }
 
@@ -148,8 +132,7 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *ud
  *
  * Returns: a flag indicating if udev is active.
  **/
-_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
-{
+_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) {
         return access("/run/udev/control", F_OK) >= 0;
 }
 
@@ -161,8 +144,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
  *
  * Returns: a flag indicating if udev is currently handling events.
  **/
-_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
-{
+_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) {
         return access("/run/udev/queue", F_OK) < 0;
 }
 
@@ -178,8 +160,7 @@ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
  * Returns: a flag indicating if udev is currently handling events.
  **/
 _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
-                                               unsigned long long int start, unsigned long long int end)
-{
+                                                        unsigned long long int start, unsigned long long int end) {
         return udev_queue_get_queue_is_empty(udev_queue);
 }
 
@@ -193,8 +174,7 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_
  *
  * Returns: a flag indicating if udev is currently handling events.
  **/
-_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
-{
+_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) {
         return udev_queue_get_queue_is_empty(udev_queue);
 }
 
@@ -206,8 +186,7 @@ _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, un
  *
  * Returns: NULL.
  **/
-_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
-{
+_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) {
         errno = ENODATA;
         return NULL;
 }
@@ -219,8 +198,9 @@ _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_qu
  * Returns: a file descriptor to watch for a queue to become empty.
  */
 _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
-        int fd;
-        int r;
+        _cleanup_close_ int fd = -1;
+
+        assert_return(udev_queue, -EINVAL);
 
         if (udev_queue->fd >= 0)
                 return udev_queue->fd;
@@ -229,15 +209,11 @@ _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
         if (fd < 0)
                 return -errno;
 
-        r = inotify_add_watch(fd, "/run/udev" , IN_DELETE);
-        if (r < 0) {
-                r = -errno;
-                close(fd);
-                return r;
-        }
+        if (inotify_add_watch(fd, "/run/udev" , IN_DELETE) < 0)
+                return -errno;
 
-        udev_queue->fd = fd;
-        return fd;
+        udev_queue->fd = TAKE_FD(fd);
+        return udev_queue->fd;
 }
 
 /**
@@ -249,7 +225,7 @@ _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
 _public_ int udev_queue_flush(struct udev_queue *udev_queue) {
         int r;
 
-        assert(udev_queue);
+        assert_return(udev_queue, -EINVAL);
 
         if (udev_queue->fd < 0)
                 return -EINVAL;
index 8af97fe16d4f046f0b57512a88b836eddc48a364..4554b922e3fbeb8668a30b23acbd56f04d1d577f 100644 (file)
@@ -18,9 +18,6 @@
 /**
  * SECTION:libudev
  * @short_description: libudev context
- *
- * The context contains the default values read from the udev config file,
- * and is passed to all library operations.
  */
 
 /**
  * Opaque object representing the library context.
  */
 struct udev {
-        int refcount;
-        void (*log_fn)(struct udev *udev,
-                       int priority, const char *file, int line, const char *fn,
-                       const char *format, va_list args);
+        unsigned n_ref;
         void *userdata;
 };
 
@@ -46,8 +40,8 @@ struct udev {
  * Returns: stored userdata
  **/
 _public_ void *udev_get_userdata(struct udev *udev) {
-        if (udev == NULL)
-                return NULL;
+        assert_return(udev, NULL);
+
         return udev->userdata;
 }
 
@@ -59,8 +53,9 @@ _public_ void *udev_get_userdata(struct udev *udev) {
  * Store custom @userdata in the library context.
  **/
 _public_ void udev_set_userdata(struct udev *udev, void *userdata) {
-        if (udev == NULL)
+        if (!udev)
                 return;
+
         udev->userdata = userdata;
 }
 
@@ -77,12 +72,15 @@ _public_ void udev_set_userdata(struct udev *udev, void *userdata) {
 _public_ struct udev *udev_new(void) {
         struct udev *udev;
 
-        udev = new0(struct udev, 1);
+        udev = new(struct udev, 1);
         if (!udev) {
                 errno = ENOMEM;
                 return NULL;
         }
-        udev->refcount = 1;
+
+        *udev = (struct udev) {
+                .n_ref = 1,
+        };
 
         return udev;
 }
@@ -95,12 +93,7 @@ _public_ struct udev *udev_new(void) {
  *
  * Returns: the passed udev library context
  **/
-_public_ struct udev *udev_ref(struct udev *udev) {
-        if (udev == NULL)
-                return NULL;
-        udev->refcount++;
-        return udev;
-}
+DEFINE_PUBLIC_TRIVIAL_REF_FUNC(struct udev, udev);
 
 /**
  * udev_unref:
@@ -112,11 +105,17 @@ _public_ struct udev *udev_ref(struct udev *udev) {
  * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise.
  **/
 _public_ struct udev *udev_unref(struct udev *udev) {
-        if (udev == NULL)
+        if (!udev)
                 return NULL;
-        udev->refcount--;
-        if (udev->refcount > 0)
+
+        assert(udev->n_ref > 0);
+        udev->n_ref--;
+        if (udev->n_ref > 0)
+                /* This is different from our convetion, but let's keep backward
+                 * compatibility. So, do not use DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC()
+                 * macro to define this function. */
                 return udev;
+
         return mfree(udev);
 }
 
@@ -128,10 +127,11 @@ _public_ struct udev *udev_unref(struct udev *udev) {
  * This function is deprecated.
  *
  **/
-_public_ void udev_set_log_fn(struct udev *udev,
-                     void (*log_fn)(struct udev *udev,
-                                    int priority, const char *file, int line, const char *fn,
-                                    const char *format, va_list args)) {
+_public_ void udev_set_log_fn(
+                        struct udev *udev,
+                        void (*log_fn)(struct udev *udev,
+                                       int priority, const char *file, int line, const char *fn,
+                                       const char *format, va_list args)) {
         return;
 }
 
index fa4eaeb9690f84240a1366a41b9c7f58deebc17b..fa2a35d1f93397346bb41ac71eebcb9f26b0e158 100644 (file)
@@ -90,7 +90,7 @@ const char *udev_device_get_action(struct udev_device *udev_device);
 unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
 unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
 const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
-int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
+int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value);
 int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
 
 /*
index 1daaa8b450b8113ef9cae597a5cd3fa8e81fe822..8fe64b918450d57b0d8a9307700bc1d007d9f0cb 100644 (file)
@@ -12,6 +12,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "fd-util.h"
+#include "format-table.h"
 #include "format-util.h"
 #include "pager.h"
 #include "process-util.h"
@@ -26,6 +27,7 @@ static const char* arg_who = NULL;
 static const char* arg_why = "Unknown reason";
 static const char* arg_mode = NULL;
 static bool arg_no_pager = false;
+static bool arg_legend = true;
 
 static enum {
         ACTION_INHIBIT,
@@ -60,11 +62,10 @@ static int inhibit(sd_bus *bus, sd_bus_error *error) {
         return r;
 }
 
-static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
+static int print_inhibitors(sd_bus *bus) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *what, *who, *why, *mode;
-        unsigned int uid, pid;
-        unsigned n = 0;
+        _cleanup_(table_unrefp) Table *table = NULL;
         int r;
 
         (void) pager_open(arg_no_pager, false);
@@ -75,44 +76,76 @@ static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
                         "/org/freedesktop/login1",
                         "org.freedesktop.login1.Manager",
                         "ListInhibitors",
-                        error,
+                        &error,
                         &reply,
                         "");
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Could not get active inhibitors: %s", bus_error_message(&error, r));
+
+        table = table_new("WHO", "UID", "USER", "PID", "COMM", "WHAT", "WHY", "MODE");
+        if (!table)
+                return log_oom();
+
+        /* If there's not enough space, shorten the "WHY" column, as it's little more than an explaining comment. */
+        (void) table_set_weight(table, TABLE_HEADER_CELL(6), 20);
 
         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
+        for (;;) {
                 _cleanup_free_ char *comm = NULL, *u = NULL;
+                const char *what, *who, *why, *mode;
+                uint32_t uid, pid;
+
+                r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+                if (r == 0)
+                        break;
 
                 if (arg_mode && !streq(mode, arg_mode))
                         continue;
 
-                get_process_comm(pid, &comm);
+                (void) get_process_comm(pid, &comm);
                 u = uid_to_name(uid);
 
-                printf("     Who: %s (UID "UID_FMT"/%s, PID "PID_FMT"/%s)\n"
-                       "    What: %s\n"
-                       "     Why: %s\n"
-                       "    Mode: %s\n\n",
-                       who, uid, strna(u), pid, strna(comm),
-                       what,
-                       why,
-                       mode);
-
-                n++;
+                r = table_add_many(table,
+                                   TABLE_STRING, who,
+                                   TABLE_UINT32, uid,
+                                   TABLE_STRING, strna(u),
+                                   TABLE_UINT32, pid,
+                                   TABLE_STRING, strna(comm),
+                                   TABLE_STRING, what,
+                                   TABLE_STRING, why,
+                                   TABLE_STRING, mode);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add table row: %m");
         }
-        if (r < 0)
-                return bus_log_parse_error(r);
 
         r = sd_bus_message_exit_container(reply);
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        printf("%u inhibitors listed.\n", n);
+        if (table_get_rows(table) > 1) {
+                r = table_set_sort(table, (size_t) 1, (size_t) 0, (size_t) 5, (size_t) 6, (size_t) -1);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to sort table: %m");
+
+                table_set_header(table, arg_legend);
+
+                r = table_print(table, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to show table: %m");
+        }
+
+        if (arg_legend) {
+                if (table_get_rows(table) > 1)
+                        printf("\n%zu inhibitors listed.\n", table_get_rows(table) - 1);
+                else
+                        printf("No inhibitors.\n");
+        }
+
         return 0;
 }
 
@@ -129,6 +162,7 @@ static int help(void) {
                "  -h --help               Show this help\n"
                "     --version            Show package version\n"
                "     --no-pager           Do not pipe output into a pager\n"
+               "     --no-legend          Do not show the headers and footers\n"
                "     --what=WHAT          Operations to inhibit, colon separated list of:\n"
                "                          shutdown, sleep, idle, handle-power-key,\n"
                "                          handle-suspend-key, handle-hibernate-key,\n"
@@ -155,6 +189,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_MODE,
                 ARG_LIST,
                 ARG_NO_PAGER,
+                ARG_NO_LEGEND,
         };
 
         static const struct option options[] = {
@@ -166,6 +201,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "mode",         required_argument, NULL, ARG_MODE         },
                 { "list",         no_argument,       NULL, ARG_LIST         },
                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
+                { "no-legend",    no_argument,       NULL, ARG_NO_LEGEND       },
                 {}
         };
 
@@ -208,6 +244,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_no_pager = true;
                         break;
 
+                case ARG_NO_LEGEND:
+                        arg_legend = false;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -227,7 +267,6 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
 
@@ -248,14 +287,13 @@ int main(int argc, char *argv[]) {
 
         if (arg_action == ACTION_LIST) {
 
-                r = print_inhibitors(bus, &error);
+                r = print_inhibitors(bus);
                 pager_close();
-                if (r < 0) {
-                        log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
+                if (r < 0)
                         return EXIT_FAILURE;
-                }
 
         } else {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_close_ int fd = -1;
                 _cleanup_free_ char *w = NULL;
                 pid_t pid;
index 94b33aef7d13dc4ccdc7c470dca22119a64bd749..5453ebb0a1d66e42fc49b11f7815ff520bb932a5 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "acl-util.h"
 #include "alloc-util.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
 #include "dirent-util.h"
 #include "escape.h"
 #include "fd-util.h"
@@ -193,11 +193,7 @@ int devnode_acl_all(const char *seat,
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+        FOREACH_DEVICE(e, d) {
                 const char *node, *sn;
 
                 if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
@@ -210,12 +206,8 @@ int devnode_acl_all(const char *seat,
                 if (sd_device_get_devname(d, &node) < 0)
                         continue;
 
-                n = strdup(node);
-                if (!n)
-                        return -ENOMEM;
-
-                log_debug("Found udev node %s for seat %s", n, seat);
-                r = set_consume(nodes, n);
+                log_debug("Found udev node %s for seat %s", node, seat);
+                r = set_put_strdup(nodes, node);
                 if (r < 0)
                         return r;
         }
index 5fc4f29127e2402ff5084bf751358fdd9786cb45..87506088a1c4a52b16a1fc60f936a349d438a307 100644 (file)
@@ -13,7 +13,7 @@
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "conf-parser.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
 #include "fd-util.h"
 #include "logind.h"
 #include "parse-util.h"
@@ -218,14 +218,14 @@ int manager_add_button(Manager *m, const char *name, Button **_button) {
 }
 
 int manager_process_seat_device(Manager *m, sd_device *d) {
-        const char *action = NULL;
+        const char *action;
         Device *device;
         int r;
 
         assert(m);
 
-        (void) sd_device_get_property_value(d, "ACTION", &action);
-        if (streq_ptr(action, "remove")) {
+        if (sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
+            streq(action, "remove")) {
                 const char *syspath;
 
                 r = sd_device_get_syspath(d, &syspath);
@@ -285,7 +285,7 @@ int manager_process_seat_device(Manager *m, sd_device *d) {
 }
 
 int manager_process_button_device(Manager *m, sd_device *d) {
-        const char *action = NULL, *sysname;
+        const char *action, *sysname;
         Button *b;
         int r;
 
@@ -295,8 +295,8 @@ int manager_process_button_device(Manager *m, sd_device *d) {
         if (r < 0)
                 return r;
 
-        (void) sd_device_get_property_value(d, "ACTION", &action);
-        if (streq_ptr(action, "remove")) {
+        if (sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
+            streq(action, "remove")) {
 
                 b = hashmap_get(m->buttons, sysname);
                 if (!b)
@@ -305,7 +305,7 @@ int manager_process_button_device(Manager *m, sd_device *d) {
                 button_free(b);
 
         } else {
-                const char *sn = NULL;
+                const char *sn;
 
                 r = manager_add_button(m, sysname, &b);
                 if (r < 0)
@@ -571,11 +571,7 @@ static int manager_count_external_displays(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+        FOREACH_DEVICE(e, d) {
                 sd_device *p;
                 const char *status, *enabled, *dash, *nn, *i, *subsys;
                 bool external = false;
@@ -592,12 +588,10 @@ static int manager_count_external_displays(Manager *m) {
                 if (sd_device_get_sysname(d, &nn) < 0)
                         continue;
 
-                /* Ignore internal displays: the type is encoded in
-                 * the sysfs name, as the second dash separated item
-                 * (the first is the card name, the last the connector
-                 * number). We implement a whitelist of external
-                 * displays here, rather than a whitelist, to ensure
-                 * we don't block suspends too eagerly. */
+                /* Ignore internal displays: the type is encoded in the sysfs name, as the second dash separated item
+                 * (the first is the card name, the last the connector number). We implement a blacklist of external
+                 * displays here, rather than a whitelist of internal ones, to ensure we don't block suspends too
+                 * eagerly. */
                 dash = strchr(nn, '-');
                 if (!dash)
                         continue;
index 47cf62cb3d88f160e12575e6786ede245ce60ae9..5035bb5bdfed1c57960fa486a492060a05c6ad89 100644 (file)
@@ -14,7 +14,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
 #include "dirent-util.h"
 #include "efivars.h"
 #include "escape.h"
@@ -1210,11 +1210,7 @@ static int trigger_device(Manager *m, sd_device *d) {
                         return r;
         }
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+        FOREACH_DEVICE(e, d) {
                 _cleanup_free_ char *t = NULL;
                 const char *p;
 
index fbba792ed699c1e4fcec8f70ed100318c38f4a0c..e1e3e8b49809ac959e2be1f055f79c6b8acb79ad 100644 (file)
@@ -255,10 +255,10 @@ static DeviceType detect_device_type(sd_device *dev) {
             sd_device_get_subsystem(dev, &subsystem) < 0)
                 return type;
 
-        if (streq_ptr(subsystem, "drm")) {
+        if (streq(subsystem, "drm")) {
                 if (startswith(sysname, "card"))
                         type = DEVICE_TYPE_DRM;
-        } else if (streq_ptr(subsystem, "input")) {
+        } else if (streq(subsystem, "input")) {
                 if (startswith(sysname, "event"))
                         type = DEVICE_TYPE_EVDEV;
         }
@@ -268,17 +268,18 @@ static DeviceType detect_device_type(sd_device *dev) {
 
 static int session_device_verify(SessionDevice *sd) {
         _cleanup_(sd_device_unrefp) sd_device *p = NULL;
+        const char *sp, *node;
         sd_device *dev;
-        const char *sp = NULL, *node;
         int r;
 
-        if (sd_device_new_from_devnum(&p, 'c', sd->dev) < 0)
-                return -ENODEV;
+        r = sd_device_new_from_devnum(&p, 'c', sd->dev);
+        if (r < 0)
+                return r;
 
         dev = p;
 
-        (void) sd_device_get_syspath(dev, &sp);
-        if (sd_device_get_devname(dev, &node) < 0)
+        if (sd_device_get_syspath(dev, &sp) < 0 ||
+            sd_device_get_devname(dev, &node) < 0)
                 return -EINVAL;
 
         /* detect device type so we can find the correct sysfs parent */
index c487fbc6988469fda4a1258043846f262858e05b..e90c8575dcd821b6edcf63b28b170d647a8017c0 100644 (file)
@@ -13,7 +13,7 @@
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "def.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "format-util.h"
@@ -175,11 +175,7 @@ static int manager_enumerate_devices(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+        FOREACH_DEVICE(e, d) {
                 int k;
 
                 k = manager_process_seat_device(m, d);
@@ -214,11 +210,7 @@ static int manager_enumerate_buttons(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+        FOREACH_DEVICE(e, d) {
                 int k;
 
                 k = manager_process_button_device(m, d);
@@ -588,7 +580,7 @@ static int manager_dispatch_vcsa_udev(sd_event_source *s, int fd, uint32_t reven
         if (sd_device_get_sysname(d, &name) >= 0 &&
             startswith(name, "vcsa") &&
             sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
-            streq_ptr(action, "remove"))
+            streq(action, "remove"))
                 seat_preallocate_vts(m->seat0);
 
         return 0;
index 5d2a6ad209d06d02cc1d26bf04692703ccb08dfe..192c95107b76fd0697e1b784c480a621430eb674 100644 (file)
@@ -40,7 +40,7 @@ static int show_sysfs_one(
                 max_width = n_columns;
 
         while (*i_dev < n_dev) {
-                const char *sysfs, *sn, *name = NULL, *subsystem = NULL, *sysname = NULL;
+                const char *sysfs, *sn, *name = NULL, *subsystem, *sysname;
                 _cleanup_free_ char *k = NULL, *l = NULL;
                 size_t lookahead;
                 bool is_master;
@@ -53,7 +53,10 @@ static int show_sysfs_one(
                         sn = "seat0";
 
                 /* Explicitly also check for tag 'seat' here */
-                if (!streq(seat, sn) || sd_device_has_tag(dev_list[*i_dev], "seat") <= 0) {
+                if (!streq(seat, sn) ||
+                    sd_device_has_tag(dev_list[*i_dev], "seat") <= 0 ||
+                    sd_device_get_subsystem(dev_list[*i_dev], &subsystem) < 0 ||
+                    sd_device_get_sysname(dev_list[*i_dev], &sysname) < 0) {
                         (*i_dev)++;
                         continue;
                 }
@@ -63,9 +66,6 @@ static int show_sysfs_one(
                 if (sd_device_get_sysattr_value(dev_list[*i_dev], "name", &name) < 0)
                         (void) sd_device_get_sysattr_value(dev_list[*i_dev], "id", &name);
 
-                (void) sd_device_get_subsystem(dev_list[*i_dev], &subsystem);
-                (void) sd_device_get_sysname(dev_list[*i_dev], &sysname);
-
                 /* Look if there's more coming after this */
                 for (lookahead = *i_dev + 1; lookahead < n_dev; lookahead++) {
                         const char *lookahead_sysfs;
@@ -127,8 +127,8 @@ static int show_sysfs_one(
 
 int show_sysfs(const char *seat, const char *prefix, unsigned n_columns, OutputFlags flags) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        size_t n_dev = 0, n_allocated = 0, i = 0;
-        sd_device *d, **dev_list = NULL;
+        size_t n_dev = 0, i = 0;
+        sd_device **dev_list;
         int r;
 
         if (n_columns <= 0)
@@ -155,27 +155,12 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns, OutputF
         if (r < 0)
                 return r;
 
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
-                const char *syspath;
-
-                if (sd_device_get_syspath(d, &syspath) < 0)
-                        continue;
-
-                if (!GREEDY_REALLOC(dev_list, n_allocated, n_dev + 2))
-                        return -ENOMEM;
-
-                dev_list[n_dev++] = sd_device_ref(d);
-                dev_list[n_dev] = NULL;
-        }
+        dev_list = device_enumerator_get_devices(e, &n_dev);
 
-        if (n_dev > 0)
+        if (dev_list && n_dev > 0)
                 show_sysfs_one(seat, dev_list, &i, n_dev, "/", prefix, n_columns, flags);
         else
                 printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), "(none)");
 
-        for (i = 0; i < n_dev; i++)
-                sd_device_unref(dev_list[i]);
-        free(dev_list);
-
         return 0;
 }
index 83787015d2954b272575cfff3d08a9b8c15cc119..47ccb352bf2549c6439e857c7bf24b797787aeb3 100644 (file)
@@ -2378,10 +2378,8 @@ typedef struct TransferInfo {
         double progress;
 } TransferInfo;
 
-static int compare_transfer_info(const void *a, const void *b) {
-        const TransferInfo *x = a, *y = b;
-
-        return strcmp(x->local, y->local);
+static int compare_transfer_info(const TransferInfo *a, const TransferInfo *b) {
+        return strcmp(a->local, b->local);
 }
 
 static int list_transfers(int argc, char *argv[], void *userdata) {
@@ -2449,7 +2447,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
+        typesafe_qsort(transfers, n_transfers, compare_transfer_info);
 
         if (arg_legend && n_transfers > 0)
                 printf("%-*s %-*s %-*s %-*s %-*s\n",
index 5ce9644861ffb1d14bdb5b6ab3eaae4d2e1af596..3cdf86ed4782fb21c03a64c5f141c34851f79d7a 100644 (file)
@@ -5,10 +5,10 @@
 #include "sd-bus.h"
 #include "sd-device.h"
 
-#include "device-enumerator-private.h"
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "device-util.h"
 #include "dirent-util.h"
 #include "escape.h"
 #include "fd-util.h"
@@ -1372,17 +1372,15 @@ struct item {
         char* columns[_COLUMN_MAX];
 };
 
-static int compare_item(const void *a, const void *b) {
-        const struct item *x = a, *y = b;
-
-        if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
+static int compare_item(const struct item *a, const struct item *b) {
+        if (a->columns[COLUMN_NODE] == b->columns[COLUMN_NODE])
                 return 0;
-        if (!x->columns[COLUMN_NODE])
+        if (!a->columns[COLUMN_NODE])
                 return 1;
-        if (!y->columns[COLUMN_NODE])
+        if (!b->columns[COLUMN_NODE])
                 return -1;
 
-        return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
+        return path_compare(a->columns[COLUMN_NODE], b->columns[COLUMN_NODE]);
 }
 
 static int list_devices(void) {
@@ -1420,11 +1418,7 @@ static int list_devices(void) {
         if (r < 0)
                 return log_error_errno(r, "Failed to add property match: %m");
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return log_error_errno(r, "Failed to enumerate devices: %m");
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+        FOREACH_DEVICE(e, d) {
                 struct item *j;
 
                 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
@@ -1489,7 +1483,7 @@ static int list_devices(void) {
                 goto finish;
         }
 
-        qsort_safe(items, n, sizeof(struct item), compare_item);
+        typesafe_qsort(items, n, compare_item);
 
         (void) pager_open(arg_no_pager, false);
 
index 3d81b72eed334a4bccdd1c54a81caea10d1cc1ee..c4a8fc8bc4aeb1ef21b8db240857efaf7e49ea7d 100644 (file)
@@ -39,16 +39,13 @@ static bool arg_legend = true;
 static bool arg_all = false;
 
 static char *link_get_type_string(unsigned short iftype, sd_device *d) {
-        const char *t;
+        const char *t, *devtype;
         char *p;
 
-        if (d) {
-                const char *devtype = NULL;
-
-                (void) sd_device_get_devtype(d, &devtype);
-                if (!isempty(devtype))
-                        return strdup(devtype);
-        }
+        if (d &&
+            sd_device_get_devtype(d, &devtype) >= 0 &&
+            !isempty(devtype))
+                return strdup(devtype);
 
         t = arphrd_to_name(iftype);
         if (!t)
@@ -104,10 +101,8 @@ typedef struct LinkInfo {
         bool has_mtu:1;
 } LinkInfo;
 
-static int link_info_compare(const void *a, const void *b) {
-        const LinkInfo *x = a, *y = b;
-
-        return x->ifindex - y->ifindex;
+static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
+        return CMP(a->ifindex, b->ifindex);
 }
 
 static int decode_link(sd_netlink_message *m, LinkInfo *info) {
@@ -190,7 +185,7 @@ static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) {
                         c++;
         }
 
-        qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
+        typesafe_qsort(links, c, link_info_compare);
 
         *ret = TAKE_PTR(links);
 
@@ -230,7 +225,7 @@ static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) {
                         c++;
         }
 
-        qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
+        typesafe_qsort(links, c, link_info_compare);
 
         *ret = TAKE_PTR(links);
 
@@ -770,12 +765,10 @@ static int link_status_one(
                 (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
                 (void) sd_device_get_property_value(d, "ID_PATH", &path);
 
-                r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
-                if (r < 0)
+                if (sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
                         (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
 
-                r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
-                if (r < 0)
+                if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) < 0)
                         (void) sd_device_get_property_value(d, "ID_MODEL", &model);
         }
 
index 0aa7a190c46a3aa12c888438879e7487afd2caaa..518d3e8f1ff52ba58f6096b1a1f1faa8c3b6a22a 100644 (file)
@@ -103,12 +103,77 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
         return sd_radv_start(radv);
 }
 
-static Network *dhcp6_reset_pd_prefix_network(Link *link) {
-        assert(link);
-        assert(link->manager);
-        assert(link->manager->networks);
+static int dhcp6_route_remove_cb(sd_netlink *nl, sd_netlink_message *m,
+                                 void *userdata) {
+        Link *l = userdata;
+        int r;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0)
+                log_link_debug_errno(l, r, "Received error on unreachable route removal for DHCPv6 delegated subnetl: %m");
+
+        l = link_unref(l);
+
+        return 0;
+}
+
+int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
+        int r;
+        sd_dhcp6_lease *lease;
+        union in_addr_union pd_prefix;
+        uint8_t pd_prefix_len;
+        uint32_t lifetime_preferred, lifetime_valid;
+
+        r = sd_dhcp6_client_get_lease(client, &lease);
+        if (r < 0)
+                return r;
+
+        sd_dhcp6_lease_reset_pd_prefix_iter(lease);
+
+        while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
+                                     &lifetime_preferred,
+                                     &lifetime_valid) >= 0) {
+                _cleanup_free_ char *buf = NULL;
+                _cleanup_free_ Route *route;
+
+                if (pd_prefix_len > 64)
+                        continue;
+
+                (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
+                if (pd_prefix_len < 64) {
+                        r = route_new(&route);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Cannot create unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
+                                                       strnull(buf),
+                                                       pd_prefix_len);
+                                continue;
+                        }
+
+                        route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
+                                  0, 0, 0, &route);
+                        route_update(route, NULL, 0, NULL, NULL, 0, 0,
+                                     RTN_UNREACHABLE);
+
+                        r = route_remove(route, link, dhcp6_route_remove_cb);
+                        if (r < 0) {
+                                (void) in_addr_to_string(AF_INET6,
+                                                         &pd_prefix, &buf);
+
+                                log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+                                                       strnull(buf),
+                                                       pd_prefix_len);
+                                route_free(route);
+                                continue;
+                        }
+                        link = link_ref(link);
+
+                        log_link_debug(link, "Removing unreachable route %s/%u",
+                                       strnull(buf), pd_prefix_len);
+                }
+        }
 
-        return link->manager->networks;
+        return 0;
 }
 
 static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
@@ -184,39 +249,28 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
                         return r;
         }
 
-        if (n_used < n_prefixes) {
-                Route *route;
-                uint64_t n = n_used;
-
-                r = route_new(&route);
-                if (r < 0)
-                        return r;
-
-                route->family = AF_INET6;
+        return 0;
+}
 
-                while (n < n_prefixes) {
-                        route_update(route, &prefix, pd_prefix_len, NULL, NULL,
-                                     0, 0, RTN_UNREACHABLE);
+static int dhcp6_route_add_cb(sd_netlink *nl, sd_netlink_message *m,
+                              void *userdata) {
+        Link *l = userdata;
+        int r;
 
-                        r = route_configure(route, dhcp6_link, NULL);
-                        if (r < 0) {
-                                route_free(route);
-                                return r;
-                        }
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r !=  -EEXIST)
+                log_link_debug_errno(l, r, "Received error when adding unreachable route for DHCPv6 delegated subnet: %m");
 
-                        r = in_addr_prefix_next(AF_INET6, &prefix, pd_prefix_len);
-                        if (r < 0)
-                                return r;
-                }
-        }
+        l = link_unref(l);
 
-        return n_used;
+        return 0;
 }
 
+
 static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
         int r;
         sd_dhcp6_lease *lease;
-        struct in6_addr pd_prefix;
+        union in_addr_union pd_prefix;
         uint8_t pd_prefix_len;
         uint32_t lifetime_preferred, lifetime_valid;
         _cleanup_free_ char *buf = NULL;
@@ -226,27 +280,62 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
         if (r < 0)
                 return r;
 
-        dhcp6_reset_pd_prefix_network(link);
         sd_dhcp6_lease_reset_pd_prefix_iter(lease);
 
-        while (sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len,
+        while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
                                      &lifetime_preferred,
                                      &lifetime_valid) >= 0) {
 
                 if (pd_prefix_len > 64) {
-                        (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
+                        (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
                         log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
                                        strnull(buf), pd_prefix_len);
                         continue;
                 }
 
                 if (pd_prefix_len < 48) {
-                        (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
+                        (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
                         log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
                                        strnull(buf), pd_prefix_len);
                 }
 
-                r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix,
+                if (pd_prefix_len < 64) {
+                        Route *route = NULL;
+
+                        (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
+                        r = route_new(&route);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Cannot create unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+                                                       strnull(buf),
+                                                       pd_prefix_len);
+                                continue;
+                        }
+
+                        route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
+                                  0, 0, 0, &route);
+                        route_update(route, NULL, 0, NULL, NULL, 0, 0,
+                                     RTN_UNREACHABLE);
+
+                        r = route_configure(route, link, dhcp6_route_add_cb);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
+                                                       strnull(buf),
+                                                       pd_prefix_len);
+                                route_free(route);
+                                continue;
+                        }
+                        link = link_ref(link);
+
+                        route_free(route);
+
+                        log_link_debug(link, "Configuring unreachable route for %s/%u",
+                                       strnull(buf), pd_prefix_len);
+
+                } else
+                        log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
+
+                r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix.in6,
                                                pd_prefix_len,
                                                lifetime_preferred,
                                                lifetime_valid);
@@ -364,6 +453,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
                 if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
                         log_link_warning(link, "DHCPv6 lease lost");
 
+                (void) dhcp6_lease_pd_prefix_lost(client, link);
                 (void) manager_dhcp6_prefix_remove_all(link->manager, link);
 
                 link->dhcp6_configured = false;
@@ -403,11 +493,12 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
 }
 
 int dhcp6_request_address(Link *link, int ir) {
-        int r, inf_req;
+        int r, inf_req, pd;
         bool running;
 
         assert(link);
         assert(link->dhcp6_client);
+        assert(link->network);
         assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
 
         r = sd_dhcp6_client_is_running(link->dhcp6_client);
@@ -416,6 +507,21 @@ int dhcp6_request_address(Link *link, int ir) {
         else
                 running = r;
 
+        r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd);
+        if (r < 0)
+                return r;
+
+        if (pd && ir && link->network->dhcp6_force_pd_other_information) {
+                log_link_debug(link, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set");
+
+                r = sd_dhcp6_client_set_address_request(link->dhcp6_client,
+                                                        false);
+                if (r < 0 )
+                        return r;
+
+                ir = false;
+        }
+
         if (running) {
                 r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
                 if (r < 0)
index dcf722a63dca70764d22d39193781e0cbf4b57e8..b686011da405a773aff61d7a21a1be9e42b5cc55 100644 (file)
@@ -165,6 +165,7 @@ int dhcp4_set_client_identifier(Link *link);
 int dhcp4_set_promote_secondaries(Link *link);
 int dhcp6_configure(Link *link);
 int dhcp6_request_address(Link *link, int ir);
+int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
 
 const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
index 27a4f6db611302a5d06617a88439d2452da633af..bdb1aacf7fdf9d42c3f6d6f8fe24a61775cd2f0d 100644 (file)
@@ -1240,27 +1240,15 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
 }
 
 static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
-                                       void *userdata) {
+                                  void *userdata) {
         Link *l = userdata;
         int r;
-        union in_addr_union prefix;
-        _cleanup_free_ char *buf = NULL;
 
         r = sd_netlink_message_get_errno(m);
-        if (r != 0) {
+        if (r < 0 && r != -EEXIST)
                 log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
-                return 0;
-        }
-
-        r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
-        if (r < 0) {
-                log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while adding route: %m");
-                return 0;
-        }
 
-        (void) in_addr_to_string(AF_INET6, &prefix, &buf);
-        log_link_debug(l, "Added DHCPv6 Prefix Deleagtion route %s/64",
-                       strnull(buf));
+        l = link_unref(l);
 
         return 0;
 }
@@ -1268,6 +1256,7 @@ static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
 int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
         int r;
         Route *route;
+        _cleanup_free_ char *buf = NULL;
 
         assert_return(m, -EINVAL);
         assert_return(m->dhcp6_prefixes, -ENODATA);
@@ -1282,6 +1271,11 @@ int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
         if (r < 0)
                 return r;
 
+        (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
+        log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
+
+        link = link_ref(link);
+
         return hashmap_put(m->dhcp6_prefixes, addr, link);
 }
 
@@ -1289,24 +1283,12 @@ static int dhcp6_route_remove_callback(sd_netlink *nl, sd_netlink_message *m,
                                        void *userdata) {
         Link *l = userdata;
         int r;
-        union in_addr_union prefix;
-        _cleanup_free_ char *buf = NULL;
 
         r = sd_netlink_message_get_errno(m);
-        if (r != 0) {
+        if (r < 0)
                 log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
-                return 0;
-        }
 
-        r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
-        if (r < 0) {
-                log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while removing route: %m");
-                return 0;
-        }
-
-        (void) in_addr_to_string(AF_INET6, &prefix, &buf);
-        log_link_debug(l, "Removed DHCPv6 Prefix Delegation route %s/64",
-                       strnull(buf));
+        l = link_unref(l);
 
         return 0;
 }
@@ -1315,6 +1297,7 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
         Link *l;
         int r;
         Route *route;
+        _cleanup_free_ char *buf = NULL;
 
         assert_return(m, -EINVAL);
         assert_return(m->dhcp6_prefixes, -ENODATA);
@@ -1327,8 +1310,17 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
         (void) sd_radv_remove_prefix(l->radv, addr, 64);
         r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
                       0, 0, 0, &route);
-        if (r >= 0)
-                (void) route_remove(route, l, dhcp6_route_remove_callback);
+        if (r < 0)
+                return r;
+
+        r = route_remove(route, l, dhcp6_route_remove_callback);
+        if (r < 0)
+                return r;
+
+        (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
+        log_link_debug(l, "Removing prefix route %s/64", strnull(buf));
+
+        l = link_ref(l);
 
         return 0;
 }
@@ -1452,11 +1444,18 @@ void manager_free(Manager *m) {
                 network_free(network);
 
         while ((link = hashmap_first(m->dhcp6_prefixes)))
-                link_unref(link);
+                manager_dhcp6_prefix_remove_all(m, link);
         hashmap_free(m->dhcp6_prefixes);
 
-        while ((link = hashmap_first(m->links)))
+        while ((link = hashmap_first(m->links))) {
+                if (link->dhcp6_client)
+                        (void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client,
+                                                          link);
+
+                hashmap_remove(m->links, INT_TO_PTR(link->ifindex));
+
                 link_unref(link);
+        }
         hashmap_free(m->links);
 
         set_free(m->links_requesting_uuid);
index 357231152e0649c4f02fa4fc3144921a781d0fab..a7c94d1dc49143812adbe65f5b6a59c9a875f84f 100644 (file)
@@ -138,6 +138,7 @@ DHCP.UseTimezone,                       config_parse_bool,
 DHCP.IAID,                              config_parse_iaid,                              0,                             offsetof(Network, iaid)
 DHCP.ListenPort,                        config_parse_uint16,                            0,                             offsetof(Network, dhcp_client_port)
 DHCP.RapidCommit,                       config_parse_bool,                              0,                             offsetof(Network, rapid_commit)
+DHCP.ForceDHCPv6PDOtherInformation,    config_parse_bool,                              0,                             offsetof(Network, dhcp6_force_pd_other_information)
 IPv6AcceptRA.UseDNS,                    config_parse_bool,                              0,                             offsetof(Network, ipv6_accept_ra_use_dns)
 IPv6AcceptRA.UseDomains,                config_parse_dhcp_use_domains,                  0,                             offsetof(Network, ipv6_accept_ra_use_domains)
 IPv6AcceptRA.RouteTable,                config_parse_uint32,                            0,                             offsetof(Network, ipv6_accept_ra_route_table)
index 6bfd8d5dd5fd3f4045b3aa592744141138c337a7..1be7d467353b92e6a6d9d1b1b36b840b749b6dbe 100644 (file)
@@ -171,6 +171,9 @@ struct Network {
         struct in6_addr *router_dns;
         unsigned n_router_dns;
         char **router_search_domains;
+        bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
+                                                  RA flag is set, see RFC 7084,
+                                                  WPD-4 */
 
         /* Bridge Support */
         int use_bpdu;
index 31112a8a961baa948ad3f4a3b59024a03a7f97a3..6e169e0fca00c0d82f9ce56f6d37990c036f0db6 100644 (file)
@@ -10,6 +10,7 @@
 #include "network-internal.h"
 #include "networkd-manager.h"
 #include "string-util.h"
+#include "tests.h"
 
 static void test_deserialize_in_addr(void) {
         _cleanup_free_ struct in_addr *addresses = NULL;
@@ -223,6 +224,8 @@ int main(void) {
         _cleanup_(sd_device_unrefp) sd_device *loopback = NULL;
         int ifindex, r;
 
+        test_setup_logging(LOG_INFO);
+
         test_deserialize_in_addr();
         test_deserialize_dhcp_routes();
         test_address_equality();
@@ -232,7 +235,8 @@ int main(void) {
 
         r = test_load_config(manager);
         if (r == -EPERM)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("Cannot load configuration");
+        assert_se(r == 0);
 
         assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
         assert_se(loopback);
index 9920f516b7a895fdb71ff0b3d2a6e54b937cf72b..d112471587752eb5966f86186292904d804de581 100644 (file)
@@ -9,6 +9,7 @@
 #include "network-internal.h"
 #include "networkd-manager.h"
 #include "string-util.h"
+#include "tests.h"
 
 static void test_rule_serialization(const char *title, const char *ruleset, const char *expected) {
         char pattern[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX",
@@ -57,9 +58,7 @@ static void test_rule_serialization(const char *title, const char *ruleset, cons
 int main(int argc, char **argv) {
         _cleanup_free_ char *p = NULL;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_rule_serialization("basic parsing",
                                 "RULE=from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1/2 table=10", NULL);
index 4a3cd29094a8a9695622c54eb1e6c1154680d39e..f7ec077f7b8410dd00d1ee085d1bce17dbfd77b7 100644 (file)
@@ -373,7 +373,7 @@ static int mount_legacy_cgns_supported(
                         if (!target)
                                 return log_oom();
 
-                        r = symlink_idempotent(controller, target);
+                        r = symlink_idempotent(controller, target, false);
                         if (r == -EINVAL)
                                 return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
                         if (r < 0)
@@ -482,7 +482,7 @@ static int mount_legacy_cgns_unsupported(
                         if (r < 0)
                                 return r;
 
-                        r = symlink_idempotent(combined, target);
+                        r = symlink_idempotent(combined, target, false);
                         if (r == -EINVAL)
                                 return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
                         if (r < 0)
index 995022272a0f9afabf2afe885268cdd63867e44b..5bef6aef598f7c6d221aef28d74a0ed52141858f 100644 (file)
@@ -69,20 +69,14 @@ void custom_mount_free_all(CustomMount *l, size_t n) {
         free(l);
 }
 
-static int custom_mount_compare(const void *a, const void *b) {
-        const CustomMount *x = a, *y = b;
+static int custom_mount_compare(const CustomMount *a, const CustomMount *b) {
         int r;
 
-        r = path_compare(x->destination, y->destination);
+        r = path_compare(a->destination, b->destination);
         if (r != 0)
                 return r;
 
-        if (x->type < y->type)
-                return -1;
-        if (x->type > y->type)
-                return 1;
-
-        return 0;
+        return CMP(a->type, b->type);
 }
 
 static bool source_path_is_valid(const char *p) {
@@ -116,7 +110,7 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) {
         assert(l || n == 0);
 
         /* Order the custom mounts, and make sure we have a working directory */
-        qsort_safe(l, n, sizeof(CustomMount), custom_mount_compare);
+        typesafe_qsort(l, n, custom_mount_compare);
 
         for (i = 0; i < n; i++) {
                 CustomMount *m = l + i;
index cd2c39ac7c6467d040c2a070eea3f9e3def5953a..e3bfe851e301861aa8d61ea0d46dfd1162a08a24 100644 (file)
@@ -2934,7 +2934,8 @@ static int outer_child(
                         }
                 }
 
-                log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
+                if (!arg_quiet)
+                        log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
         }
 
         if (dissected_image) {
index 8e29d3e806990095ea267a2cb25a4c933a5aead7..b50f0990d842d5044e0baf3c734ea0a8c17107d1 100644 (file)
@@ -5,15 +5,14 @@
 #include "log.h"
 #include "nspawn-patch-uid.h"
 #include "user-util.h"
+#include "tests.h"
 #include "util.h"
 
 int main(int argc, char *argv[]) {
         uid_t shift, range;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         if (argc != 4) {
                 log_error("Expected PATH SHIFT RANGE parameters.");
index 2c8514a72a883875ffc57f6bb6a1c1ba4e75fb10..86a9a58c5b97c628844a572db780c4a23ab89b64 100644 (file)
@@ -114,32 +114,25 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
 
 #if HAVE_GCRYPT
 
-static int rr_compare(const void *a, const void *b) {
-        DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
+static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
+        const DnsResourceRecord *x = *a, *y = *b;
         size_t m;
         int r;
 
         /* Let's order the RRs according to RFC 4034, Section 6.3 */
 
         assert(x);
-        assert(*x);
-        assert((*x)->wire_format);
+        assert(x->wire_format);
         assert(y);
-        assert(*y);
-        assert((*y)->wire_format);
+        assert(y->wire_format);
 
-        m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
+        m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
 
-        r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
+        r = memcmp(DNS_RESOURCE_RECORD_RDATA(x), DNS_RESOURCE_RECORD_RDATA(y), m);
         if (r != 0)
                 return r;
 
-        if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
-                return -1;
-        else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
-                return 1;
-
-        return 0;
+        return CMP(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
 }
 
 static int dnssec_rsa_verify_raw(
@@ -806,7 +799,7 @@ int dnssec_verify_rrset(
                 return -ENODATA;
 
         /* Bring the RRs into canonical order */
-        qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
+        typesafe_qsort(list, n, rr_compare);
 
         f = open_memstream(&sig_data, &sig_size);
         if (!f)
index 83acf3b880b170bec75db385a2aa2885f587067a..d5e74e49378a7b507f6fbc1601035809a7f0bfe2 100644 (file)
@@ -244,7 +244,7 @@ struct DnsResourceRecord {
         };
 };
 
-static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) {
+static inline const void* DNS_RESOURCE_RECORD_RDATA(const DnsResourceRecord *rr) {
         if (!rr)
                 return NULL;
 
@@ -255,7 +255,7 @@ static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) {
         return (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset;
 }
 
-static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(DnsResourceRecord *rr) {
+static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(const DnsResourceRecord *rr) {
         if (!rr)
                 return 0;
         if (!rr->wire_format)
@@ -265,7 +265,7 @@ static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(DnsResourceRecord *rr) {
         return rr->wire_format_size - rr->wire_format_rdata_offset;
 }
 
-static inline uint8_t DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(DnsResourceRecord *rr) {
+static inline uint8_t DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(const DnsResourceRecord *rr) {
         assert(rr);
         assert(rr->key->type == DNS_TYPE_OPT);
 
index bf5b07cdd3b0548290cecb6ec7c0aa0346e88e28..dc6b74618937c15aa52658dde93b9d24fb5b915c 100644 (file)
@@ -464,10 +464,8 @@ static int dns_trust_anchor_load_files(
         return 0;
 }
 
-static int domain_name_cmp(const void *a, const void *b) {
-        char **x = (char**) a, **y = (char**) b;
-
-        return dns_name_compare_func(*x, *y);
+static int domain_name_cmp(char * const *a, char * const *b) {
+        return dns_name_compare_func(*a, *b);
 }
 
 static int dns_trust_anchor_dump(DnsTrustAnchor *d) {
@@ -497,7 +495,7 @@ static int dns_trust_anchor_dump(DnsTrustAnchor *d) {
                 if (!l)
                         return log_oom();
 
-                qsort_safe(l, set_size(d->negative_by_name), sizeof(char*), domain_name_cmp);
+                typesafe_qsort(l, set_size(d->negative_by_name), domain_name_cmp);
 
                 j = strv_join(l, " ");
                 if (!j)
index 71a30ae8f8fce6a31bfbd1a3502b964f0f753a65..e70138181a9b1d730c3e3643b0e564c77a938eae 100644 (file)
@@ -53,50 +53,41 @@ eaddrinuse:
         return 0;
 }
 
-static int mdns_rr_compare(const void *a, const void *b) {
-        DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
+static int mdns_rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
+        DnsResourceRecord *x = *(DnsResourceRecord **) a, *y = *(DnsResourceRecord **) b;
         size_t m;
         int r;
 
         assert(x);
-        assert(*x);
         assert(y);
-        assert(*y);
 
-        if (CLEAR_CACHE_FLUSH((*x)->key->class) < CLEAR_CACHE_FLUSH((*y)->key->class))
-                return -1;
-        else if (CLEAR_CACHE_FLUSH((*x)->key->class) > CLEAR_CACHE_FLUSH((*y)->key->class))
-                return 1;
+        r = CMP(CLEAR_CACHE_FLUSH(x->key->class), CLEAR_CACHE_FLUSH(y->key->class));
+        if (r != 0)
+                return r;
 
-        if ((*x)->key->type < (*y)->key->type)
-                return -1;
-        else if ((*x)->key->type > (*y)->key->type)
-                return 1;
+        r = CMP(x->key->type, y->key->type);
+        if (r != 0)
+                return r;
 
-        r = dns_resource_record_to_wire_format(*x, false);
+        r = dns_resource_record_to_wire_format(x, false);
         if (r < 0) {
                 log_warning_errno(r, "Can't wire-format RR: %m");
                 return 0;
         }
 
-        r = dns_resource_record_to_wire_format(*y, false);
+        r = dns_resource_record_to_wire_format(y, false);
         if (r < 0) {
                 log_warning_errno(r, "Can't wire-format RR: %m");
                 return 0;
         }
 
-        m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
+        m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
 
-        r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
+        r = memcmp(DNS_RESOURCE_RECORD_RDATA(x), DNS_RESOURCE_RECORD_RDATA(y), m);
         if (r != 0)
                 return r;
 
-        if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
-                return -1;
-        else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
-                return 1;
-
-        return 0;
+        return CMP(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
 }
 
 static int proposed_rrs_cmp(DnsResourceRecord **x, unsigned x_size, DnsResourceRecord **y, unsigned y_size) {
@@ -151,7 +142,7 @@ static int mdns_packet_extract_matching_rrs(DnsPacket *p, DnsResourceKey *key, D
                         list[n++] = p->answer->items[i].rr;
         }
         assert(n == size);
-        qsort_safe(list, size, sizeof(DnsResourceRecord*), mdns_rr_compare);
+        typesafe_qsort(list, size, mdns_rr_compare);
 
         *ret_rrs = TAKE_PTR(list);
 
@@ -171,7 +162,8 @@ static int mdns_do_tiebreak(DnsResourceKey *key, DnsAnswer *answer, DnsPacket *p
 
         DNS_ANSWER_FOREACH(rr, answer)
                 our[i++] = rr;
-        qsort_safe(our, size, sizeof(DnsResourceRecord*), mdns_rr_compare);
+
+        typesafe_qsort(our, size, mdns_rr_compare);
 
         r = mdns_packet_extract_matching_rrs(p, key, &remote);
         if (r < 0)
index 36b82a4c926eae84f94d87a7201b76620ffc8ba6..7939c2d2fe8d229f353f751380c03840f76997e7 100644 (file)
@@ -149,7 +149,7 @@ static int wait_for_initialized(
                 if (r < 0)
                         continue;
 
-                if (sd_device_get_sysname(t, &name) >= 0 && streq_ptr(name, sysname)) {
+                if (sd_device_get_sysname(t, &name) >= 0 && streq(name, sysname)) {
                         *ret = TAKE_PTR(t);
                         return 0;
                 }
index 47a7dbafbd2c9ee9ecc5fd555089ddbcdba085cc..8d5a4211448298c3f8450a4b8ad1941219f36206 100644 (file)
@@ -202,10 +202,8 @@ int boot_loader_read_conf(const char *path, BootConfig *config) {
         return 0;
 }
 
-static int boot_entry_compare(const void *a, const void *b) {
-        const BootEntry *aa = a, *bb = b;
-
-        return str_verscmp(aa->filename, bb->filename);
+static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
+        return str_verscmp(a->filename, b->filename);
 }
 
 int boot_entries_find(const char *dir, BootEntry **ret_entries, size_t *ret_n_entries) {
@@ -234,7 +232,7 @@ int boot_entries_find(const char *dir, BootEntry **ret_entries, size_t *ret_n_en
                 n++;
         }
 
-        qsort_safe(array, n, sizeof(BootEntry), boot_entry_compare);
+        typesafe_qsort(array, n, boot_entry_compare);
 
         *ret_entries = array;
         *ret_n_entries = n;
index e1354b0d0f31d358454d9bb55b430a308923f338..4becc8c944dc3e555295fcdb7490b6fcd2235192 100644 (file)
@@ -2206,13 +2206,8 @@ static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
         free(cg);
 }
 
-static int cgroup_info_compare_func(const void *a, const void *b) {
-        const struct CGroupInfo *x = *(const struct CGroupInfo* const*) a, *y = *(const struct CGroupInfo* const*) b;
-
-        assert(x);
-        assert(y);
-
-        return strcmp(x->cgroup_path, y->cgroup_path);
+static int cgroup_info_compare_func(struct CGroupInfo * const *a, struct CGroupInfo * const *b) {
+        return strcmp((*a)->cgroup_path, (*b)->cgroup_path);
 }
 
 static int dump_processes(
@@ -2249,7 +2244,7 @@ static int dump_processes(
                         pids[n++] = PTR_TO_PID(pidp);
 
                 assert(n == hashmap_size(cg->pids));
-                qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+                typesafe_qsort(pids, n, pid_compare_func);
 
                 width = DECIMAL_STR_WIDTH(pids[n-1]);
 
@@ -2291,7 +2286,7 @@ static int dump_processes(
                 LIST_FOREACH(siblings, child, cg->children)
                         children[n++] = child;
                 assert(n == cg->n_children);
-                qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func);
+                typesafe_qsort(children, n, cgroup_info_compare_func);
 
                 if (n_columns != 0)
                         n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
@@ -2378,7 +2373,7 @@ static int dump_extra_processes(
         if (n == 0)
                 return 0;
 
-        qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+        typesafe_qsort(pids, n, pid_compare_func);
         width = DECIMAL_STR_WIDTH(pids[n-1]);
 
         for (k = 0; k < n; k++) {
index 1b58744d8eb2a163bfebf1161026779bc0621ee2..80f4606ba4ee1fbd15d32ddb6371dcd34263b3fd 100644 (file)
@@ -65,7 +65,7 @@ int bus_connect_transport_systemd(BusTransport transport, const char *host, bool
 
 typedef int (*bus_message_print_t) (const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all);
 
-int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *fmt, ...);
+int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) _printf_(4,5);
 int bus_message_print_all_properties(sd_bus_message *m, bus_message_print_t func, char **filter, bool value, bool all, Set **found_properties);
 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, bus_message_print_t func, char **filter, bool value, bool all, Set **found_properties);
 
index 4d1a90bd55da78f66bb11156ac9586fd733bf1e5..801cf133f94d259cc8cf145f3868a99de8db4686 100644 (file)
@@ -38,7 +38,7 @@ static void show_pid_array(
         if (n_pids == 0)
                 return;
 
-        qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
+        typesafe_qsort(pids, n_pids, pid_compare_func);
 
         /* Filter duplicates */
         for (j = 0, i = 1; i < n_pids; i++) {
index 5e48ee79813cdf69064a5f4ff72f2d8d255d240e..0429a55a9c80638e1f01f734c81fac8c25ebe907 100644 (file)
@@ -14,8 +14,8 @@
 #include "copy.h"
 #include "crypt-util.h"
 #include "def.h"
-#include "device-enumerator-private.h"
 #include "device-nodes.h"
+#include "device-util.h"
 #include "dissect-image.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -278,13 +278,9 @@ int dissect_image(
                 if (r < 0)
                         return r;
 
-                r = device_enumerator_scan_devices(e);
-                if (r < 0)
-                        return r;
-
                 /* Count the partitions enumerated by the kernel */
                 n = 0;
-                FOREACH_DEVICE_AND_SUBSYSTEM(e, q) {
+                FOREACH_DEVICE(e, q) {
                         dev_t qn;
 
                         if (sd_device_get_devnum(q, &qn) < 0)
@@ -350,11 +346,7 @@ int dissect_image(
                 e = sd_device_enumerator_unref(e);
         }
 
-        r = device_enumerator_scan_devices(e);
-        if (r < 0)
-                return r;
-
-        FOREACH_DEVICE_AND_SUBSYSTEM(e, q) {
+        FOREACH_DEVICE(e, q) {
                 unsigned long long pflags;
                 blkid_partition pp;
                 const char *node;
index fcc0db8b0b306b6b5e52c041ea50d8856ad8a245..e96748efde0cb5e44f25062be12282c5f5faea54 100644 (file)
@@ -563,10 +563,8 @@ static int boot_id_hex(const char s[4]) {
         return id;
 }
 
-static int cmp_uint16(const void *_a, const void *_b) {
-        const uint16_t *a = _a, *b = _b;
-
-        return (int)*a - (int)*b;
+static int cmp_uint16(const uint16_t *a, const uint16_t *b) {
+        return CMP(*a, *b);
 }
 
 int efi_get_boot_options(uint16_t **options) {
@@ -604,7 +602,7 @@ int efi_get_boot_options(uint16_t **options) {
                 list[count++] = id;
         }
 
-        qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
+        typesafe_qsort(list, count, cmp_uint16);
 
         *options = TAKE_PTR(list);
 
index 4fedeb17e3665d56a04bdb33a5d1f09c7dbb6cc8..df56492e7b04c5aad264cc5c9b97b7a36f0910c4 100644 (file)
@@ -378,14 +378,21 @@ int grow_machine_directory(void) {
                 new_size = old_size + max_add;
 
         r = btrfs_resize_loopback("/var/lib/machines", new_size, true);
-        if (r <= 0)
-                return r;
+        if (r < 0)
+                return log_debug_errno(r, "Failed to resize loopback: %m");
+        if (r == 0)
+                return 0;
 
         /* Also bump the quota, of both the subvolume leaf qgroup, as
          * well as of any subtree quota group by the same id but a
          * higher level, if it exists. */
-        (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
-        (void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
+        r = btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
+        if (r < 0)
+                log_debug_errno(r, "Failed to set btrfs limit: %m");
+
+        r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
+        if (r < 0)
+                log_debug_errno(r, "Failed to set btrfs subtree limit: %m");
 
         log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
         return 1;
index 94f4629b1b8b69cbcf97e6b478af49e223be5dc6..10fe6a088c326a962b68808b3f556945a021bfaa 100644 (file)
@@ -7,7 +7,9 @@
 #include <util.h>
 
 #include "alloc-util.h"
+#include "env-util.h"
 #include "fileio.h"
+#include "log.h"
 #include "path-util.h"
 #include "strv.h"
 #include "tests.h"
@@ -76,3 +78,33 @@ const char* get_catalog_dir(void) {
         }
         return env;
 }
+
+bool slow_tests_enabled(void) {
+        int r;
+
+        r = getenv_bool("SYSTEMD_SLOW_TESTS");
+        if (r >= 0)
+                return r;
+
+        if (r != -ENXIO)
+                log_warning_errno(r, "Cannot parse $SYSTEMD_SLOW_TESTS, ignoring.");
+        return SYSTEMD_SLOW_TESTS_DEFAULT;
+}
+
+void test_setup_logging(int level) {
+        log_set_max_level(level);
+        log_parse_environment();
+        log_open();
+}
+
+int log_tests_skipped(const char *message) {
+        log_notice("%s: %s, skipping tests.",
+                   program_invocation_short_name, message);
+        return EXIT_TEST_SKIP;
+}
+
+int log_tests_skipped_errno(int r, const char *message) {
+        log_notice_errno(r, "%s: %s, skipping tests: %m",
+                         program_invocation_short_name, message);
+        return EXIT_TEST_SKIP;
+}
index 0d5e6a8386ab4438a1121c5d32eaefc53c562ef5..549959edf2e5b023fe7ed9a4b16d70f55cc2da08 100644 (file)
@@ -4,3 +4,7 @@
 char* setup_fake_runtime_dir(void);
 const char* get_testdata_dir(void);
 const char* get_catalog_dir(void);
+bool slow_tests_enabled(void);
+void test_setup_logging(int level);
+int log_tests_skipped(const char *message);
+int log_tests_skipped_errno(int r, const char *message);
index 434ce6ff4defa973fb0b1f5d39b6ae49f7a0c2b8..5fa7bd277eb7d22233f55ade847a241abc7ec1de 100644 (file)
@@ -8,6 +8,7 @@
 #include "macro.h"
 #include "uid-range.h"
 #include "user-util.h"
+#include "util.h"
 
 static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
         assert(range);
@@ -45,20 +46,14 @@ static void uid_range_coalesce(UidRange **p, unsigned *n) {
         }
 }
 
-static int uid_range_compare(const void *a, const void *b) {
-        const UidRange *x = a, *y = b;
-
-        if (x->start < y->start)
-                return -1;
-        if (x->start > y->start)
-                return 1;
+static int uid_range_compare(const UidRange *a, const UidRange *b) {
+        int r;
 
-        if (x->nr < y->nr)
-                return -1;
-        if (x->nr > y->nr)
-                return 1;
+        r = CMP(a->start, b->start);
+        if (r != 0)
+                return r;
 
-        return 0;
+        return CMP(a->nr, b->nr);
 }
 
 int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
@@ -102,7 +97,7 @@ int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
                 x->nr = nr;
         }
 
-        qsort(*p, *n, sizeof(UidRange), uid_range_compare);
+        typesafe_qsort(*p, *n, uid_range_compare);
         uid_range_coalesce(p, n);
 
         return *n;
index 3b8d4578397e41c4dfc8c3260bb006d92e491fc6..042a44656fe1ff2462c177a73057ae7ab36638c2 100644 (file)
@@ -167,7 +167,7 @@ static int execute(char **modes, char **states) {
                         return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;
         }
 
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
 
         log_struct(LOG_INFO,
                    "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
@@ -184,7 +184,7 @@ static int execute(char **modes, char **states) {
                    "SLEEP=%s", arg_verb);
 
         arguments[1] = (char*) "post";
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
 
         return r;
 }
index 1543038d2137b29a9e6b52d6d528076faf4399a7..ce5cbe7c13d11d116d198c86caed0a5fd887c0bf 100644 (file)
@@ -316,25 +316,24 @@ static bool install_client_side(void) {
         return false;
 }
 
-static int compare_unit_info(const void *a, const void *b) {
-        const UnitInfo *u = a, *v = b;
+static int compare_unit_info(const UnitInfo *a, const UnitInfo *b) {
         const char *d1, *d2;
         int r;
 
         /* First, order by machine */
-        if (!u->machine && v->machine)
+        if (!a->machine && b->machine)
                 return -1;
-        if (u->machine && !v->machine)
+        if (a->machine && !b->machine)
                 return 1;
-        if (u->machine && v->machine) {
-                r = strcasecmp(u->machine, v->machine);
+        if (a->machine && b->machine) {
+                r = strcasecmp(a->machine, b->machine);
                 if (r != 0)
                         return r;
         }
 
         /* Second, order by unit type */
-        d1 = strrchr(u->id, '.');
-        d2 = strrchr(v->id, '.');
+        d1 = strrchr(a->id, '.');
+        d2 = strrchr(b->id, '.');
         if (d1 && d2) {
                 r = strcasecmp(d1, d2);
                 if (r != 0)
@@ -342,7 +341,7 @@ static int compare_unit_info(const void *a, const void *b) {
         }
 
         /* Third, order by name */
-        return strcasecmp(u->id, v->id);
+        return strcasecmp(a->id, b->id);
 }
 
 static const char* unit_type_suffix(const char *name) {
@@ -756,7 +755,7 @@ static int list_units(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info);
+        typesafe_qsort(unit_infos, r, compare_unit_info);
         return output_units_list(unit_infos, r);
 }
 
@@ -851,7 +850,7 @@ struct socket_info {
 };
 
 static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
-        int o;
+        int r;
 
         assert(a);
         assert(b);
@@ -861,16 +860,16 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_
         if (a->machine && !b->machine)
                 return 1;
         if (a->machine && b->machine) {
-                o = strcasecmp(a->machine, b->machine);
-                if (o != 0)
-                        return o;
+                r = strcasecmp(a->machine, b->machine);
+                if (r != 0)
+                        return r;
         }
 
-        o = strcmp(a->path, b->path);
-        if (o == 0)
-                o = strcmp(a->type, b->type);
+        r = strcmp(a->path, b->path);
+        if (r == 0)
+                r = strcmp(a->type, b->type);
 
-        return o;
+        return r;
 }
 
 static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
@@ -1006,8 +1005,7 @@ static int list_sockets(int argc, char *argv[], void *userdata) {
                 listening = triggered = NULL; /* avoid cleanup */
         }
 
-        qsort_safe(socket_infos, cs, sizeof(struct socket_info),
-                   (__compar_fn_t) socket_info_compare);
+        typesafe_qsort(socket_infos, cs, socket_info_compare);
 
         output_sockets_list(socket_infos, cs);
 
@@ -1100,7 +1098,7 @@ struct timer_info {
 };
 
 static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
-        int o;
+        int r;
 
         assert(a);
         assert(b);
@@ -1110,15 +1108,14 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf
         if (a->machine && !b->machine)
                 return 1;
         if (a->machine && b->machine) {
-                o = strcasecmp(a->machine, b->machine);
-                if (o != 0)
-                        return o;
+                r = strcasecmp(a->machine, b->machine);
+                if (r != 0)
+                        return r;
         }
 
-        if (a->next_elapse < b->next_elapse)
-                return -1;
-        if (a->next_elapse > b->next_elapse)
-                return 1;
+        r = CMP(a->next_elapse, b->next_elapse);
+        if (r != 0)
+                return r;
 
         return strcmp(a->id, b->id);
 }
@@ -1311,8 +1308,7 @@ static int list_timers(int argc, char *argv[], void *userdata) {
                 };
         }
 
-        qsort_safe(timer_infos, c, sizeof(struct timer_info),
-                   (__compar_fn_t) timer_info_compare);
+        typesafe_qsort(timer_infos, c, timer_info_compare);
 
         output_timers_list(timer_infos, c);
 
@@ -1323,12 +1319,11 @@ static int list_timers(int argc, char *argv[], void *userdata) {
         return r;
 }
 
-static int compare_unit_file_list(const void *a, const void *b) {
+static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
         const char *d1, *d2;
-        const UnitFileList *u = a, *v = b;
 
-        d1 = strrchr(u->path, '.');
-        d2 = strrchr(v->path, '.');
+        d1 = strrchr(a->path, '.');
+        d2 = strrchr(b->path, '.');
 
         if (d1 && d2) {
                 int r;
@@ -1338,7 +1333,7 @@ static int compare_unit_file_list(const void *a, const void *b) {
                         return r;
         }
 
-        return strcasecmp(basename(u->path), basename(v->path));
+        return strcasecmp(basename(a->path), basename(b->path));
 }
 
 static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
@@ -1558,7 +1553,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_no_pager, false);
 
-        qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
+        typesafe_qsort(units, c, compare_unit_file_list);
         output_unit_file_list(units, c);
 
         if (install_client_side())
@@ -1680,9 +1675,7 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
         return 0;
 }
 
-static int list_dependencies_compare(const void *_a, const void *_b) {
-        const char **a = (const char**) _a, **b = (const char**) _b;
-
+static int list_dependencies_compare(char * const *a, char * const *b) {
         if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
                 return 1;
         if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
@@ -1714,7 +1707,7 @@ static int list_dependencies_one(
         if (r < 0)
                 return r;
 
-        qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+        typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
 
         STRV_FOREACH(c, deps) {
                 if (strv_contains(*units, *c)) {
@@ -1839,13 +1832,14 @@ static void free_machines_list(struct machine_info *machine_infos, int n) {
         free(machine_infos);
 }
 
-static int compare_machine_info(const void *a, const void *b) {
-        const struct machine_info *u = a, *v = b;
+static int compare_machine_info(const struct machine_info *a, const struct machine_info *b) {
+        int r;
 
-        if (u->is_host != v->is_host)
-                return u->is_host > v->is_host ? -1 : 1;
+        r = CMP(b->is_host, a->is_host);
+        if (r != 0)
+                return r;
 
-        return strcasecmp(u->name, v->name);
+        return strcasecmp(a->name, b->name);
 }
 
 static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
@@ -2033,7 +2027,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_no_pager, false);
 
-        qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
+        typesafe_qsort(machine_infos, r, compare_machine_info);
         output_machines_list(machine_infos, r);
         free_machines_list(machine_infos, r);
 
@@ -5169,7 +5163,7 @@ static int show_all(
 
         c = (unsigned) r;
 
-        qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
+        typesafe_qsort(unit_infos, c, compare_unit_info);
 
         for (u = unit_infos; u < unit_infos + c; u++) {
                 _cleanup_free_ char *p = NULL;
index 5f84439a58bbd8112064ac7f28e5083582bb0a4d..212f99cf785f97b6c0d6d9d7aa8fceb993493a5f 100644 (file)
@@ -65,10 +65,12 @@ endif
 foreach header : _systemd_headers
         foreach opt : opts
                 name = ''.join([header, ':'] + opt)
-                test('cc-' + name,
-                     check_compilation_sh,
-                     args : cc.cmd_array() + ['-c', '-x'] + opt +
-                            ['-Werror', '-include',
-                             join_paths(meson.current_source_dir(), header)])
+                if want_tests != 'false'
+                        test('cc-' + name,
+                             check_compilation_sh,
+                             args : cc.cmd_array() + ['-c', '-x'] + opt +
+                                    ['-Werror', '-include',
+                                     join_paths(meson.current_source_dir(), header)])
+                endif
         endforeach
 endforeach
index 3a51c135d4fea3e21819d866f1aeeed537ab17f1..406db8866dc7247a8032729a69db80acf6478bd6 100644 (file)
@@ -68,7 +68,7 @@ int sd_device_has_tag(sd_device *device, const char *tag);
 int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
 int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
 
-int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *value);
+int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value);
 
 /* device enumerator */
 
index fa36dca9090dd3beba0be088caa3cc12d8f38e2b..7024ad84d696b35ddc35a573ceb67234446f6c78 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <inttypes.h>
 #include <net/ethernet.h>
-#include <stdbool.h>
 #include <sys/types.h>
 
 #include "sd-dhcp6-lease.h"
@@ -120,8 +119,14 @@ int sd_dhcp6_client_get_information_request(
 int sd_dhcp6_client_set_request_option(
                 sd_dhcp6_client *client,
                 uint16_t option);
+int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
+                                          int *delegation);
 int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
-                                          bool delegation);
+                                          int delegation);
+int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client,
+                                        int *request);
+int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
+                                        int request);
 
 int sd_dhcp6_client_get_lease(
                 sd_dhcp6_client *client,
index e82c993ab4d6b471c06bf60ed266886b3d17870a..21a8c3b12b98a79c2b3d7090e240c8c4903d0ef2 100644 (file)
@@ -6,7 +6,8 @@ test_hashmap_ordered_c = custom_target(
         input : [awkscript, 'test-hashmap-plain.c'],
         output : 'test-hashmap-ordered.c',
         command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
-        capture : true)
+        capture : true,
+        build_by_default : want_tests != 'false')
 
 test_include_dir = include_directories('.')
 
@@ -26,14 +27,16 @@ test_libsystemd_sym_c = custom_target(
         input : [libsystemd_sym_path] + systemd_headers,
         output : 'test-libsystemd-sym.c',
         command : [generate_sym_test_py, libsystemd_sym_path] + systemd_headers,
-        capture : true)
+        capture : true,
+        build_by_default : want_tests != 'false')
 
 test_libudev_sym_c = custom_target(
         'test-libudev-sym.c',
         input : [libudev_sym_path, libudev_h_path],
         output : 'test-libudev-sym.c',
         command : [generate_sym_test_py, '@INPUT0@', '@INPUT1@'],
-        capture : true)
+        capture : true,
+        build_by_default : want_tests != 'false')
 
 test_dlopen_c = files('test-dlopen.c')
 
@@ -627,7 +630,7 @@ tests += [
           libblkid,
           libkmod,
           libacl],
-         '', 'manual'],
+         '', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'],
 
         [['src/test/test-id128.c'],
          [],
index 6bc0a28a42af6aeba805940a1a18ce622d732d94..8c43bfc750ec265e9a58d63ada0836e453732daf 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "architecture.h"
 #include "log.h"
+#include "tests.h"
 #include "util.h"
 #include "virt.h"
 
@@ -9,6 +10,8 @@ int main(int argc, char *argv[]) {
         int a, v;
         const char *p;
 
+        test_setup_logging(LOG_INFO);
+
         assert_se(architecture_from_string("") < 0);
         assert_se(architecture_from_string(NULL) < 0);
         assert_se(architecture_from_string("hoge") < 0);
@@ -18,7 +21,7 @@ int main(int argc, char *argv[]) {
 
         v = detect_virtualization();
         if (IN_SET(v, -EPERM, -EACCES))
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("Cannot detect virtualization");
 
         assert_se(v >= 0);
 
index d2afd92f63b808f6f369efa4a126f6c714a5e37d..6ae84cd6fcfcf38daebba54fe8f9517fb46b3975 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "barrier.h"
 #include "util.h"
+#include "tests.h"
 
 /* 20ms to test deadlocks; All timings use multiples of this constant as
  * alarm/sleep timers. If this timeout is too small for slow machines to perform
@@ -419,18 +420,10 @@ TEST_BARRIER(test_barrier_pending_exit,
         TEST_BARRIER_WAIT_SUCCESS(pid2));
 
 int main(int argc, char *argv[]) {
-        /*
-         * This test uses real-time alarms and sleeps to test for CPU races
-         * explicitly. This is highly fragile if your system is under load. We
-         * already increased the BASE_TIME value to make the tests more robust,
-         * but that just makes the test take significantly longer. Hence,
-         * disable the test by default, so it will not break CI.
-         */
-        if (argc < 2)
-                return EXIT_TEST_SKIP;
+        test_setup_logging(LOG_INFO);
 
-        log_parse_environment();
-        log_open();
+        if (!slow_tests_enabled())
+                return log_tests_skipped("slow tests are disabled");
 
         test_barrier_sync();
         test_barrier_wait_next();
index ef39304b9fb7a7c590554225988f7c49fbdc434c..d45ca8c9204fc7e29bec69ca09d3048aba5fd930 100644 (file)
@@ -4,6 +4,7 @@
 #include "boot-timestamps.h"
 #include "efivars.h"
 #include "log.h"
+#include "tests.h"
 #include "util.h"
 
 static int test_acpi_fpdt(void) {
@@ -81,8 +82,7 @@ static int test_boot_timestamps(void) {
 int main(int argc, char* argv[]) {
         int p, q, r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         p = test_acpi_fpdt();
         assert(p >= 0);
@@ -91,5 +91,8 @@ int main(int argc, char* argv[]) {
         r = test_boot_timestamps();
         assert(r >= 0);
 
-        return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP;
+        if (p == 0 && q == 0 && r == 0)
+                return log_tests_skipped("access to firmware variables not possible");
+
+        return EXIT_SUCCESS;
 }
index 6f4a22a1ccc9616af91968287927233618d40717..2fb7968dfd074b8cccc92846be4cff5153ac886d 100644 (file)
@@ -28,15 +28,11 @@ int main(int argc, char *argv[]) {
         char log_buf[65535];
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice("cgroupfs not available, skipping tests");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         assert_se(set_unit_path(get_testdata_dir()) >= 0);
         assert_se(runtime_dir = setup_fake_runtime_dir());
@@ -47,16 +43,12 @@ int main(int argc, char *argv[]) {
         r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn));
         assert(r == 0);
 
-        if (getuid() != 0) {
-                log_notice("Not running as root, skipping kernel related tests.");
-                return EXIT_TEST_SKIP;
-        }
+        if (getuid() != 0)
+                return log_tests_skipped("not running as root");
 
         r = bpf_firewall_supported();
-        if (r == BPF_FIREWALL_UNSUPPORTED) {
-                log_notice("BPF firewalling not supported, skipping");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == BPF_FIREWALL_UNSUPPORTED)
+                return log_tests_skipped("BPF firewalling not supported");
         assert_se(r > 0);
 
         if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI)
@@ -110,9 +102,8 @@ int main(int argc, char *argv[]) {
         unit_dump(u, stdout, NULL);
 
         r = bpf_firewall_compile(u);
-        if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM ))
-                /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */
-                return EXIT_TEST_SKIP;
+        if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM))
+                return log_tests_skipped("Kernel doesn't support the necessary bpf bits (masked out via seccomp?)");
         assert_se(r >= 0);
 
         assert(u->ip_bpf_ingress);
index 791b3928fe7600e7119696dbb8bb2e324ef570ee..789d19cf7f79d886b990332d823957ccc06f3078 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "bus-util.h"
 #include "log.h"
+#include "tests.h"
 
 static void test_name_async(unsigned n_messages) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
@@ -78,9 +79,7 @@ static void test_destroy_callback(void) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_name_async(0);
         test_name_async(20);
index af6d808b6dabcb5b13e67345defee1b72eaa1d0e..730dbf8cbdaaca84d5c748991c30ce3f45efa232 100644 (file)
@@ -14,6 +14,7 @@
 #include "fileio.h"
 #include "macro.h"
 #include "parse-util.h"
+#include "tests.h"
 #include "util.h"
 
 static uid_t test_uid = -1;
@@ -91,10 +92,9 @@ static int setup_tests(bool *run_ambient) {
         int r;
 
         nobody = getpwnam(NOBODY_USER_NAME);
-        if (!nobody) {
-                log_error_errno(errno, "Could not find nobody user: %m");
-                return -EXIT_TEST_SKIP;
-        }
+        if (!nobody)
+                return log_error_errno(errno, "Could not find nobody user: %m");
+
         test_uid = nobody->pw_uid;
         test_gid = nobody->pw_gid;
 
@@ -218,23 +218,20 @@ static void test_set_ambient_caps(void) {
 }
 
 int main(int argc, char *argv[]) {
-        int r;
         bool run_ambient;
 
+        test_setup_logging(LOG_INFO);
+
         test_last_cap_file();
         test_last_cap_probe();
 
-        log_parse_environment();
-        log_open();
-
         log_info("have ambient caps: %s", yes_no(ambient_capabilities_supported()));
 
         if (getuid() != 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("not running as root");
 
-        r = setup_tests(&run_ambient);
-        if (r < 0)
-                return -r;
+        if (setup_tests(&run_ambient) < 0)
+                return log_tests_skipped("setup failed");
 
         show_capabilities();
 
index 8dc1639720c26468470b51c3d4e7699699bfdd08..bab27edf5453806b7e35ac3de659e4e0458f74ce 100644 (file)
@@ -17,19 +17,18 @@ static int test_cgroup_mask(void) {
         int r;
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                puts("Skipping test: cgroupfs not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         /* Prepare the manager. */
         assert_se(set_unit_path(get_testdata_dir()) >= 0);
         assert_se(runtime_dir = setup_fake_runtime_dir());
         r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
         if (IN_SET(r, -EPERM, -EACCES)) {
-                puts("manager_new: Permission denied. Skipping test.");
-                return EXIT_TEST_SKIP;
+                log_error_errno(r, "manager_new: %m");
+                return log_tests_skipped("cannot create manager");
         }
+
         assert_se(r >= 0);
 
         /* Turn off all kinds of default accouning, so that we can
@@ -117,13 +116,12 @@ static void test_cg_mask_to_string(void) {
 }
 
 int main(int argc, char* argv[]) {
-        int rc = 0;
+        int rc = EXIT_SUCCESS;
 
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
-        TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
         test_cg_mask_to_string();
+        TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
 
         return rc;
 }
index d49356315edbdbdd49702d424a75e243de7f350e..058cc44c42a0aab5040c74cb1705b9698078a11b 100644 (file)
@@ -14,6 +14,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "test-helper.h"
+#include "tests.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -296,7 +297,7 @@ static void test_shift_path(void) {
         test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
         test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
         test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
-        test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
+        test_shift_path_one("/foobar/waldo", "/hogehoge", "/foobar/waldo");
 }
 
 static void test_mask_supported(void) {
@@ -447,9 +448,7 @@ static void test_cg_get_keyed_attribute(void) {
 }
 
 int main(void) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_path_decode_unit();
         test_path_get_unit();
index 7ce6ee80eaa62a545ce9de7e51968399c61997ad..5c2d00af886a5ca7ff3035e55e382f3fb1c24f44 100644 (file)
@@ -26,6 +26,7 @@
 #include "strv.h"
 #include "tomoyo-util.h"
 #include "user-util.h"
+#include "tests.h"
 #include "util.h"
 #include "virt.h"
 
@@ -113,7 +114,7 @@ static void test_condition_test_path(void) {
         condition_free(condition);
 }
 
-static int test_condition_test_control_group_controller(void) {
+static void test_condition_test_control_group_controller(void) {
         Condition *condition;
         CGroupMask system_mask;
         CGroupController controller;
@@ -123,7 +124,7 @@ static int test_condition_test_control_group_controller(void) {
         r = cg_unified_flush();
         if (r < 0) {
                 log_notice_errno(r, "Skipping ConditionControlGroupController tests: %m");
-                return EXIT_TEST_SKIP;
+                return;
         }
 
         /* Invalid controllers are ignored */
@@ -180,8 +181,6 @@ static int test_condition_test_control_group_controller(void) {
         assert_se(condition);
         assert_se(!condition_test(condition));
         condition_free(condition);
-
-        return EXIT_SUCCESS;
 }
 
 static void test_condition_test_ac_power(void) {
@@ -675,9 +674,7 @@ static void test_condition_test_group(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_condition_test_path();
         test_condition_test_ac_power();
index 2ec2dfc26154c72d4815fe50f2e6394a586c5281..b69046c9c19b253c02fa090173bbc5b0fdc3d84e 100644 (file)
@@ -16,6 +16,7 @@
 #include "rm-rf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -93,9 +94,7 @@ static void test_conf_files_list(bool use_root) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_conf_files_list(false);
         test_conf_files_list(true);
index 2e8d251ac145c4ff1dbffdcc0adb6e399ce93be3..4e265374ab116548305e565cba9e2b7365f2c95e 100644 (file)
@@ -14,6 +14,7 @@
 #include "rm-rf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -254,7 +255,7 @@ static void test_copy_atomic(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         test_copy_file();
         test_copy_file_fd();
index 99b6f2eb9ea3a3a6d232bf431b675a4d80e60985..cba51e225c68c3264657081939310b8111171165 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "alloc-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_should_pass(const char *p) {
@@ -66,9 +67,7 @@ static void test_one_noutc(const char *p) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_one("17:41");
         test_one("18:42:44");
index a0a909baf0a65d0290025c805f96d4fa2ad01e50..7b32e8373f920a01ca44e3b67958c3375cbca783 100644 (file)
@@ -7,13 +7,14 @@
 #include "log.h"
 #include "loop-util.h"
 #include "string-util.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
         _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
         int r, i;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         if (argc < 2) {
                 log_error("Requires one command line argument.");
index 7fa887e4d2109b7c0202772545163f4b4903e268..cbfe5ef390388623028d6dbe2ba1ebb8895e072e 100644 (file)
@@ -4,6 +4,7 @@
 #include "dns-domain.h"
 #include "macro.h"
 #include "string-util.h"
+#include "tests.h"
 
 static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
         char buffer[buffer_sz];
@@ -687,9 +688,7 @@ static void test_dns_name_is_valid_or_address(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_dns_label_unescape();
         test_dns_label_unescape_suffix();
index 0f3e244dc1c7bdbd58b612676b83184c504298de..0673d36b6225aabb06f50b9ed886743e3f87fe9b 100644 (file)
@@ -18,24 +18,18 @@ int main(int argc, char *argv[]) {
         Job *j;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice_errno(r, "Skipping test: cgroupfs not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         /* prepare the test */
         assert_se(set_unit_path(get_testdata_dir()) >= 0);
         assert_se(runtime_dir = setup_fake_runtime_dir());
         r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
-        if (MANAGER_SKIP_TEST(r)) {
-                log_notice_errno(r, "Skipping test: manager_new: %m");
-                return EXIT_TEST_SKIP;
-        }
+        if (MANAGER_SKIP_TEST(r))
+                return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
         assert_se(manager_startup(m, NULL, NULL) >= 0);
 
index 650a9a058dd74149b82f71fd8e914591f279e9a4..4ee4aa974d73272dcc845ccd62b7e7ae54cf6ad2 100644 (file)
@@ -3,6 +3,7 @@
 #include "alloc-util.h"
 #include "escape.h"
 #include "macro.h"
+#include "tests.h"
 
 static void test_cescape(void) {
         _cleanup_free_ char *escaped;
@@ -119,9 +120,7 @@ static void test_shell_maybe_quote(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_cescape();
         test_cunescape();
index cfc8b5f88ee29abff38e7102d7fa4cacca6cf638..e74b95231dc18a5313847e52f127d4ba4e28db2f 100644 (file)
 #include "fs-util.h"
 #include "log.h"
 #include "macro.h"
+#include "path-util.h"
 #include "rm-rf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 
 static int here = 0, here2 = 0, here3 = 0;
 void *ignore_stdout_args[] = {&here, &here2, &here3};
@@ -115,9 +117,9 @@ static void test_execute_directory(bool gather_stdout) {
         assert_se(chmod(mask2e, 0755) == 0);
 
         if (gather_stdout)
-                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL);
+                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL);
         else
-                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL);
+                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL);
 
         assert_se(chdir(template_lo) == 0);
         assert_se(access("it_works", F_OK) >= 0);
@@ -182,7 +184,7 @@ static void test_execution_order(void) {
         assert_se(chmod(override, 0755) == 0);
         assert_se(chmod(masked, 0755) == 0);
 
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL);
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL);
 
         assert_se(read_full_file(output, &contents, NULL) >= 0);
         assert_se(streq(contents, "30-override\n80-foo\n90-bar\nlast\n"));
@@ -264,7 +266,7 @@ static void test_stdout_gathering(void) {
         assert_se(chmod(name2, 0755) == 0);
         assert_se(chmod(name3, 0755) == 0);
 
-        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL);
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL);
         assert_se(r >= 0);
 
         log_info("got: %s", output);
@@ -275,7 +277,7 @@ static void test_stdout_gathering(void) {
 static void test_environment_gathering(void) {
         char template[] = "/tmp/test-exec-util.XXXXXXX", **p;
         const char *dirs[] = {template, NULL};
-        const char *name, *name2, *name3;
+        const char *name, *name2, *name3, *old;
         int r;
 
         char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
@@ -321,7 +323,32 @@ static void test_environment_gathering(void) {
         assert_se(chmod(name2, 0755) == 0);
         assert_se(chmod(name3, 0755) == 0);
 
-        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL);
+        /* When booting in containers or without initramfs there might not be
+         * any PATH in the environ and if there is no PATH /bin/sh built-in
+         * PATH may leak and override systemd's DEFAULT_PATH which is not
+         * good. Force our own PATH in environment, to prevent expansion of sh
+         * built-in $PATH */
+        old = getenv("PATH");
+        r = setenv("PATH", "no-sh-built-in-path", 1);
+        assert_se(r >= 0);
+
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL);
+        assert_se(r >= 0);
+
+        STRV_FOREACH(p, env)
+                log_info("got env: \"%s\"", *p);
+
+        assert_se(streq(strv_env_get(env, "A"), "22:23:24"));
+        assert_se(streq(strv_env_get(env, "B"), "12"));
+        assert_se(streq(strv_env_get(env, "C"), "001"));
+        assert_se(streq(strv_env_get(env, "PATH"), "no-sh-built-in-path:/no/such/file"));
+
+        /* now retest with "default" path passed in, as created by
+         * manager_default_environment */
+        env = strv_free(env);
+        env = strv_new("PATH=" DEFAULT_PATH, NULL);
+
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, env);
         assert_se(r >= 0);
 
         STRV_FOREACH(p, env)
@@ -330,13 +357,14 @@ static void test_environment_gathering(void) {
         assert_se(streq(strv_env_get(env, "A"), "22:23:24"));
         assert_se(streq(strv_env_get(env, "B"), "12"));
         assert_se(streq(strv_env_get(env, "C"), "001"));
-        assert_se(endswith(strv_env_get(env, "PATH"), ":/no/such/file"));
+        assert_se(streq(strv_env_get(env, "PATH"), DEFAULT_PATH ":/no/such/file"));
+
+        /* reset environ PATH */
+        (void) setenv("PATH", old, 1);
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_execute_directory(true);
         test_execute_directory(false);
index b37e6017538e3d46c01de546c1fcc43a7812d160..c3ea5f6469ec38db4019c15d76f1e22e8b8eb842 100644 (file)
@@ -664,10 +664,8 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) {
         assert_se(tests);
 
         r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
-        if (MANAGER_SKIP_TEST(r)) {
-                log_notice_errno(r, "Skipping test: manager_new: %m");
-                return EXIT_TEST_SKIP;
-        }
+        if (MANAGER_SKIP_TEST(r))
+                return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
         assert_se(manager_startup(m, NULL, NULL) >= 0);
 
@@ -724,25 +722,19 @@ int main(int argc, char *argv[]) {
         };
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         (void) unsetenv("USER");
         (void) unsetenv("LOGNAME");
         (void) unsetenv("SHELL");
 
         /* It is needed otherwise cgroup creation fails */
-        if (getuid() != 0) {
-                puts("Skipping test: not root");
-                return EXIT_TEST_SKIP;
-        }
+        if (getuid() != 0)
+                return log_tests_skipped("not root");
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                puts("Skipping test: cgroupfs not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         assert_se(runtime_dir = setup_fake_runtime_dir());
         test_execute_path = path_join(NULL, get_testdata_dir(), "test-execute");
index a04403d7485938626284a3a4cd9e6e4ea9211011..157dc88320789b43c9f4838b191924da3c3d0e9b 100644 (file)
@@ -12,6 +12,7 @@
 #include "random-util.h"
 #include "string-util.h"
 #include "util.h"
+#include "tests.h"
 
 static void test_close_many(void) {
         int fds[3];
@@ -316,7 +317,7 @@ static void test_read_nr_open(void) {
 
 int main(int argc, char *argv[]) {
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         test_close_many();
         test_close_nointr();
index 14ba075144b10652b7fff8c5b00fb0c911448591..aa38a7d29a4e623588463f910c36adf1c2e64198 100644 (file)
@@ -16,6 +16,7 @@
 #include "process-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_parse_env_file(void) {
@@ -710,9 +711,7 @@ static void test_read_line3(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_parse_env_file();
         test_parse_multiline_env_file();
index 1b62590b49bf304e2c531ebf19cd8d11d4148897..1788e8d1ca8c262a5d50c894037ab8abc6e26c2d 100644 (file)
@@ -2,12 +2,13 @@
 
 #include "firewall-util.h"
 #include "log.h"
+#include "tests.h"
 
 #define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))}
 
 int main(int argc, char *argv[]) {
         int r;
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0);
         if (r < 0)
index f5bc131846e0e1e6e3815060d8f984962650a8b1..44d1044bf37fe96eb6054853f6a1d51634f4ac18 100644 (file)
@@ -7,23 +7,22 @@
 #include "log.h"
 #include "string-util.h"
 #include "khash.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_(khash_unrefp) khash *h = NULL, *copy = NULL;
         _cleanup_free_ char *s = NULL;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(khash_new(&h, NULL) == -EINVAL);
         assert_se(khash_new(&h, "") == -EINVAL);
 
         r = khash_supported();
         assert_se(r >= 0);
-        if (r == 0) {
-                puts("khash not supported on this kernel, skipping");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == 0)
+                return log_tests_skipped("khash not supported on this kernel");
 
         assert_se(khash_new(&h, "foobar") == -EOPNOTSUPP); /* undefined hash function */
 
index f80febce76b06ea1f98fe90b1251b2e3740615ac..82837da4f620d83d9b3af8ce33e371b26674054d 100644 (file)
@@ -1,15 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
-#include "env-util.h"
 #include "hashmap.h"
 #include "log.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "util.h"
 
-static bool arg_slow = false;
-
 void test_hashmap_funcs(void);
 
 static void test_hashmap_replace(void) {
@@ -739,15 +737,16 @@ static void test_hashmap_many(void) {
         Hashmap *h;
         unsigned i, j;
         void *v, *k;
+        bool slow = slow_tests_enabled();
         const struct {
                 const struct hash_ops *ops;
                 unsigned n_entries;
         } tests[] = {
-                { .ops = NULL,                  .n_entries = arg_slow ? 1 << 20 : 240 },
-                { .ops = &crippled_hashmap_ops, .n_entries = arg_slow ? 1 << 14 : 140 },
+                { .ops = NULL,                  .n_entries = slow ? 1 << 20 : 240 },
+                { .ops = &crippled_hashmap_ops, .n_entries = slow ? 1 << 14 : 140 },
         };
 
-        log_info("%s (%s)", __func__, arg_slow ? "slow" : "fast");
+        log_info("%s (%s)", __func__, slow ? "slow" : "fast");
 
         for (j = 0; j < ELEMENTSOF(tests); j++) {
                 assert_se(h = hashmap_new(tests[j].ops));
@@ -886,14 +885,9 @@ static void test_hashmap_reserve(void) {
 }
 
 void test_hashmap_funcs(void) {
-        int r;
-
         log_parse_environment();
         log_open();
 
-        r = getenv_bool("SYSTEMD_SLOW_TESTS");
-        arg_slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
-
         test_hashmap_copy();
         test_hashmap_get_strv();
         test_hashmap_move_one();
index fe1ca5b16f47425cb396a5be601c903bfdd68281..c0956fa4bb35d6a88f10bba9484ea4a2199920e3 100644 (file)
@@ -7,6 +7,7 @@
 #include "rm-rf.h"
 #include "special.h"
 #include "string-util.h"
+#include "tests.h"
 
 static void test_basic_mask_and_enable(const char *root) {
         const char *p;
@@ -14,7 +15,7 @@ static void test_basic_mask_and_enable(const char *root) {
         UnitFileChange *changes = NULL;
         size_t n_changes = 0;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
index 7dfc7e42724665f1033078ca3875226487ef91ed..62daaccd6229c3bdead762013b68a5c0e4a1055c 100644 (file)
@@ -4,6 +4,7 @@
 #include <string.h>
 
 #include "install.h"
+#include "tests.h"
 
 static void dump_changes(UnitFileChange *c, unsigned n) {
         unsigned i;
@@ -29,8 +30,7 @@ int main(int argc, char* argv[]) {
         size_t n_changes = 0;
         UnitFileState state = 0;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         h = hashmap_new(&string_hash_ops);
         r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
index 6cdf48a49033aa69e02572397b04e8bf603f5dad..4b658a0bdbbc70787ad154a5f6c0ba0ba2e06776 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "clean-ipc.h"
 #include "user-util.h"
+#include "tests.h"
 #include "util.h"
 
 int main(int argc, char *argv[]) {
@@ -9,11 +10,14 @@ int main(int argc, char *argv[]) {
         int r;
         const char* name = argv[1] ?: NOBODY_USER_NAME;
 
+        test_setup_logging(LOG_INFO);
+
         r = get_user_creds(&name, &uid, NULL, NULL, NULL, 0);
+        if (r == -ESRCH)
+                return log_tests_skipped("Failed to resolve user");
         if (r < 0) {
-                log_full_errno(r == -ESRCH ? LOG_NOTICE : LOG_ERR,
-                               r, "Failed to resolve \"%s\": %m", name);
-                return r == -ESRCH ? EXIT_TEST_SKIP : EXIT_FAILURE;
+                log_error_errno(r, "Failed to resolve \"%s\": %m", name);
+                return EXIT_FAILURE;
         }
 
         r = clean_ipc_by_uid(uid);
index 8f09d5ad2f3d8c7ffab7c756aca00cd807f8018d..c1ceb0bbd8b47e645a0c3112127dd6a07c0c0b39 100644 (file)
@@ -69,8 +69,7 @@ static void test_bad_input(void) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         test_basic_parsing();
         test_bad_input();
index eaea9e4c7670997c6a528c6fd4363e66f3919961..89b760fae436d2ed53b5951b34cf96f4d7c87618 100644 (file)
@@ -5,13 +5,12 @@
 
 #include "log.h"
 #include "loopback-setup.h"
+#include "tests.h"
 
 int main(int argc, char* argv[]) {
         int r;
 
-        log_open();
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         r = loopback_setup();
         if (r < 0)
index c10e1681fb971f839c88e46ce1fe62c3831ed19b..56e385aa11703bb886bd3fb63c26ba1683edbc84 100644 (file)
@@ -13,6 +13,7 @@
 #include "path-util.h"
 #include "rm-rf.h"
 #include "string-util.h"
+#include "tests.h"
 
 static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
         long unsigned flags;
@@ -295,7 +296,7 @@ static void test_mount_option_mangle(void) {
 
 int main(int argc, char *argv[]) {
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         test_mount_propagation_flags("shared", 0, MS_SHARED);
         test_mount_propagation_flags("slave", 0, MS_SLAVE);
index b202739719c58b4a4e686d667a6d936584ed666f..ab8f05076df7b4e069cb159435c52844731aea2c 100644 (file)
@@ -7,6 +7,7 @@
 #include "namespace.h"
 #include "process-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_tmpdir(const char *id, const char *A, const char *B) {
@@ -46,16 +47,14 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
         assert_se(rmdir(b) >= 0);
 }
 
-static void test_netns(void) {
+static int test_netns(void) {
         _cleanup_close_pair_ int s[2] = { -1, -1 };
         pid_t pid1, pid2, pid3;
         int r, n = 0;
         siginfo_t si;
 
-        if (geteuid() > 0) {
-                log_info("Skipping test: not root");
-                exit(EXIT_TEST_SKIP);
-        }
+        if (geteuid() > 0)
+                return log_tests_skipped("not root");
 
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
 
@@ -102,6 +101,7 @@ static void test_netns(void) {
         n += si.si_status;
 
         assert_se(n == 1);
+        return EXIT_SUCCESS;
 }
 
 int main(int argc, char *argv[]) {
@@ -109,8 +109,7 @@ int main(int argc, char *argv[]) {
         char boot_id[SD_ID128_STRING_MAX];
         _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL;
 
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         assert_se(sd_id128_get_boot(&bid) >= 0);
         sd_id128_to_string(bid, boot_id);
@@ -128,7 +127,5 @@ int main(int argc, char *argv[]) {
 
         test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
 
-        test_netns();
-
-        return 0;
+        return test_netns();
 }
index eed610b27a5ee8e26ab0e48e742a5bfe45ca0b1d..1ebe8d197202c55227a6a453b6f02023aa4bcbfe 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "macro.h"
 #include "module-util.h"
+#include "tests.h"
 #include "util.h"
 
 static int load_module(const char *mod_name) {
@@ -47,10 +48,14 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
         /* skip test if module cannot be loaded */
         r = load_module("ipip");
         if (r < 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped_errno(r, "failed to load module 'ipip'");
+
+        r = load_module("sit");
+        if (r < 0)
+                return log_tests_skipped_errno(r, "failed to load module 'sit'");
 
         if (getuid() != 0)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("not root");
 
         /* IPIP tunnel */
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
@@ -76,10 +81,6 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
 
         assert_se((m = sd_netlink_message_unref(m)) == NULL);
 
-        r = load_module("sit");
-        if (r < 0)
-                return EXIT_TEST_SKIP;
-
         /* sit */
         assert_se(sd_rtnl_message_new_link(rtnl, &n, RTM_NEWLINK, 0) >= 0);
         assert_se(n);
@@ -113,6 +114,8 @@ int main(int argc, char *argv[]) {
         sd_netlink *rtnl;
         int r;
 
+        test_setup_logging(LOG_INFO);
+
         assert_se(sd_netlink_open(&rtnl) >= 0);
         assert_se(rtnl);
 
index 4ab70f2306d3075a004e2bcd74d60630f3acf3b7..d3dbb54ca175a7ce1073527211866df5ad1fbc60 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "log.h"
 #include "namespace.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
         const char * const writable[] = {
@@ -43,7 +44,7 @@ int main(int argc, char *argv[]) {
         char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
              var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX";
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(mkdtemp(tmp_dir));
         assert_se(mkdtemp(var_tmp_dir));
index 8d8b52d7f6aa5aff4799070d67183180c6615891..c215a2e99e945787d730d83c6cd19e5f9d2b1bff 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "log.h"
 #include "os-util.h"
+#include "tests.h"
 
 static void test_path_is_os_tree(void) {
         assert_se(path_is_os_tree("/") > 0);
@@ -12,9 +13,7 @@ static void test_path_is_os_tree(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_path_is_os_tree();
 
index d6ea659d1db4f0bc2da053f5e863304a3b4c1e89..f20855935866a94118023e2985135f14f1a5e41f 100644 (file)
@@ -8,6 +8,7 @@
 #include "rm-rf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 
 static void test_paths(UnitFileScope scope) {
         char template[] = "/tmp/test-path-lookup.XXXXXXX";
@@ -78,9 +79,7 @@ static void print_generator_binary_paths(UnitFileScope scope) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_paths(UNIT_FILE_SYSTEM);
         test_paths(UNIT_FILE_USER);
index 35b27bcedd5b1e87ab9297053c3f11361c4fcd11..9ec42aae7b06bc2d41a99b7c4af4fe548eea7b11 100644 (file)
@@ -12,6 +12,7 @@
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "util.h"
 
 #define test_path_compare(a, b, result) {                 \
@@ -506,9 +507,7 @@ static void test_empty_or_root(void) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_path();
         test_path_equal_root();
index 5e78a560ffe8135ee6e6d3ddab4e21746ad5be89..0b5537b3646a27d048ccd749a5615a6ed011e3a7 100644 (file)
@@ -33,16 +33,12 @@ static int setup_test(Manager **m) {
         assert_se(m);
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice_errno(r, "Skipping test: cgroupfs not available");
-                return -EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
-        if (MANAGER_SKIP_TEST(r)) {
-                log_notice_errno(r, "Skipping test: manager_new: %m");
-                return -EXIT_TEST_SKIP;
-        }
+        if (MANAGER_SKIP_TEST(r))
+                return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
         assert_se(manager_startup(tmp, NULL, NULL) >= 0);
 
@@ -254,8 +250,7 @@ int main(int argc, char *argv[]) {
 
         umask(022);
 
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         test_path = path_join(NULL, get_testdata_dir(), "test-path");
         assert_se(set_unit_path(test_path) >= 0);
@@ -266,8 +261,8 @@ int main(int argc, char *argv[]) {
 
                 /* We create a clean environment for each test */
                 r = setup_test(&m);
-                if (r < 0)
-                        return -r;
+                if (r != 0)
+                        return r;
 
                 (*test)(m);
 
index 89c41d8ce744b51922b3afecf181ce0e86437366..f7fb5ce42262c87c9462071150b74dd8bf11a6e0 100644 (file)
 
 #define SET_SIZE 1024*4
 
-static int unsigned_compare(const void *a, const void *b) {
-        const unsigned *x = a, *y = b;
-
-        if (*x < *y)
-                return -1;
-
-        if (*x > *y)
-                return 1;
-
-        return 0;
+static int unsigned_compare(const unsigned *a, const unsigned *b) {
+        return CMP(*a, *b);
 }
 
 static void test_unsigned(void) {
@@ -39,7 +31,7 @@ static void test_unsigned(void) {
                 assert_se(prioq_put(q, UINT_TO_PTR(u), NULL) >= 0);
         }
 
-        qsort(buffer, ELEMENTSOF(buffer), sizeof(buffer[0]), unsigned_compare);
+        typesafe_qsort(buffer, ELEMENTSOF(buffer), unsigned_compare);
 
         for (i = 0; i < ELEMENTSOF(buffer); i++) {
                 unsigned u;
index 1b3b357913d9125cdea2f35c41b7cce21211b5b1..3d63493117260ff24ad3155368d6b37945bd536c 100644 (file)
@@ -24,6 +24,7 @@
 #include "string-util.h"
 #include "terminal-util.h"
 #include "test-helper.h"
+#include "tests.h"
 #include "util.h"
 #include "virt.h"
 
@@ -180,15 +181,19 @@ static void test_get_process_cmdline_harder(void) {
         _cleanup_free_ char *line = NULL;
         pid_t pid;
 
-        if (geteuid() != 0)
+        if (geteuid() != 0) {
+                log_info("Skipping %s: not root", __func__);
                 return;
+        }
 
 #if HAVE_VALGRIND_VALGRIND_H
         /* valgrind patches open(/proc//cmdline)
          * so, test_get_process_cmdline_harder fails always
          * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
-        if (RUNNING_ON_VALGRIND)
+        if (RUNNING_ON_VALGRIND) {
+                log_info("Skipping %s: running on valgrind", __func__);
                 return;
+        }
 #endif
 
         pid = fork();
@@ -587,9 +592,7 @@ static void test_ioprio_class_from_to_string(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         saved_argc = argc;
         saved_argv = argv;
index 70301a7782132da2db57a8c3e160d562e1f434e2..9652a0af05b2c3e1387a4bc7b306b01dcd50ab95 100644 (file)
@@ -3,6 +3,7 @@
 #include "hexdecoct.h"
 #include "random-util.h"
 #include "log.h"
+#include "tests.h"
 
 static void test_acquire_random_bytes(bool high_quality_required) {
         uint8_t buf[16] = {};
@@ -51,9 +52,7 @@ static void test_rdrand64(void) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_acquire_random_bytes(false);
         test_acquire_random_bytes(true);
index 60012e47d28818e38d3689891a09b4016c14b5b3..1aa178182bffb482068d1c374d85b09f1736fad9 100644 (file)
@@ -19,20 +19,18 @@ int main(int argc, char *argv[]) {
         Service *ser;
         int r;
 
+        test_setup_logging(LOG_INFO);
+
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice_errno(r, "Skipping test: cgroupfs not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         /* prepare the test */
         assert_se(set_unit_path(get_testdata_dir()) >= 0);
         assert_se(runtime_dir = setup_fake_runtime_dir());
         r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
-        if (MANAGER_SKIP_TEST(r)) {
-                log_notice_errno(r, "Skipping test: manager_new: %m");
-                return EXIT_TEST_SKIP;
-        }
+        if (MANAGER_SKIP_TEST(r))
+                return log_tests_skipped_errno(r, "manager_new");
         assert_se(r >= 0);
         assert_se(manager_startup(m, NULL, NULL) >= 0);
 
index d82cb5c1c56e6d59593dc9b6cab0c969d7eb9daf..b2ac392dac206a8e18818c48d645450dc80dc1b9 100644 (file)
@@ -20,6 +20,7 @@
 #include "seccomp-util.h"
 #include "set.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 #include "virt.h"
 
@@ -88,10 +89,14 @@ static void test_filter_sets(void) {
         unsigned i;
         int r;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
                 pid_t pid;
@@ -160,10 +165,14 @@ static void test_restrict_namespace(void) {
         assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL);
         s = mfree(s);
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping remaining tests in %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping remaining tests in %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -223,13 +232,20 @@ static void test_restrict_namespace(void) {
 static void test_protect_sysctl(void) {
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
-        if (detect_container() > 0) /* in containers _sysctl() is likely missing anyway */
+        /* in containers _sysctl() is likely missing anyway */
+        if (detect_container() > 0) {
+                log_notice("Testing in container, skipping %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -256,10 +272,14 @@ static void test_protect_sysctl(void) {
 static void test_restrict_address_families(void) {
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -339,13 +359,20 @@ static void test_restrict_address_families(void) {
 static void test_restrict_realtime(void) {
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
-        if (detect_container() > 0) /* in containers RT privs are likely missing anyway */
+        /* in containers RT privs are likely missing anyway */
+        if (detect_container() > 0) {
+                log_notice("Testing in container, skipping %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -377,10 +404,14 @@ static void test_restrict_realtime(void) {
 static void test_memory_deny_write_execute_mmap(void) {
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -421,10 +452,14 @@ static void test_memory_deny_write_execute_shmat(void) {
         int shmid;
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         shmid = shmget(IPC_PRIVATE, page_size(), 0);
         assert_se(shmid >= 0);
@@ -467,10 +502,14 @@ static void test_memory_deny_write_execute_shmat(void) {
 static void test_restrict_archs(void) {
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -501,10 +540,14 @@ static void test_restrict_archs(void) {
 static void test_load_syscall_filter_set_raw(void) {
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         pid = fork();
         assert_se(pid >= 0);
@@ -593,10 +636,14 @@ static void test_lock_personality(void) {
         unsigned long current;
         pid_t pid;
 
-        if (!is_seccomp_available())
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
                 return;
-        if (geteuid() != 0)
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
                 return;
+        }
 
         assert_se(opinionated_personality(&current) >= 0);
 
@@ -668,7 +715,7 @@ static void test_filter_sets_ordered(void) {
 
 int main(int argc, char *argv[]) {
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         test_seccomp_arch_to_string();
         test_architecture_table();
index 6caeb843f3ecf5fcb870da7dec7be4844f0f1637..59b4f719466ec4b02cd5b0bbc43699387f38a65c 100644 (file)
@@ -7,6 +7,7 @@
 #include "log.h"
 #include "selinux-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "time-util.h"
 #include "util.h"
 
@@ -92,8 +93,7 @@ int main(int argc, char **argv) {
         if (argc >= 2)
                 path = argv[1];
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         test_testing();
         test_loading();
index c9343364d43d74237e37233a23a3005a562f3bac..33c9d42e9e3711a3c7c1353dcca862a3d39eb8ce 100644 (file)
@@ -2,12 +2,14 @@
 
 #include <sys/mman.h>
 
+#if HAVE_VALGRIND_VALGRIND_H
+#  include <valgrind/valgrind.h>
+#endif
+
 #include "fd-util.h"
 #include "sigbus.h"
+#include "tests.h"
 #include "util.h"
-#if HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int fd = -1;
@@ -15,14 +17,16 @@ int main(int argc, char *argv[]) {
         void *addr = NULL;
         uint8_t *p;
 
+        test_setup_logging(LOG_INFO);
+
+#ifdef __SANITIZE_ADDRESS__
+        return log_tests_skipped("address-sanitizer is enabled");
+#endif
 #if HAVE_VALGRIND_VALGRIND_H
         if (RUNNING_ON_VALGRIND)
-                return EXIT_TEST_SKIP;
+                return log_tests_skipped("This test cannot run on valgrind");
 #endif
 
-#ifdef __SANITIZE_ADDRESS__
-        return EXIT_TEST_SKIP;
-#endif
         sigbus_install();
 
         assert_se(sigbus_pop(&addr) == 0);
index a8ad302f710089a1dba25dbe054c69181b2c5e98..2ce79f8345c460012bfdb0de0c91ebdda1ea63a1 100644 (file)
@@ -8,6 +8,7 @@
 #include "log.h"
 #include "sleep-config.h"
 #include "strv.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_parse_sleep_config(void) {
@@ -26,10 +27,8 @@ static int test_fiemap(const char *path) {
         if (fd < 0)
                 return log_error_errno(errno, "failed to open %s: %m", path);
         r = read_fiemap(fd, &fiemap);
-        if (r == -EOPNOTSUPP) {
-                log_info("Skipping test, not supported");
-                exit(EXIT_TEST_SKIP);
-        }
+        if (r == -EOPNOTSUPP)
+                exit(log_tests_skipped("Not supported"));
         if (r < 0)
                 return log_error_errno(r, "Unable to read extent map for '%s': %m", path);
         log_info("extent map information for %s:", path);
@@ -81,8 +80,7 @@ static void test_sleep(void) {
 int main(int argc, char* argv[]) {
         int i, r = 0, k;
 
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         if (getuid() != 0)
                 log_warning("This program is unlikely to work for unprivileged users");
index 19c5395b924b9e8019d943e867c3f0989ae0c292..df18a2a83c48b5a2c3a8818d4d548c4627f9405b 100644 (file)
@@ -17,6 +17,7 @@
 #include "socket-util.h"
 #include "string-util.h"
 #include "util.h"
+#include "tests.h"
 
 static void test_ifname_valid(void) {
         assert(ifname_valid("foo"));
@@ -698,7 +699,7 @@ static void test_send_emptydata(void) {
 
 int main(int argc, char *argv[]) {
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         test_ifname_valid();
 
index 9c7c352b5155fd295b623c7f3a9b4e6b92003467..a0ffdf6cb6aa54c340cdbbe854d7a852d56c628b 100644 (file)
@@ -5,6 +5,7 @@
 #include "specifier.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 
 static void test_specifier_escape_one(const char *a, const char *b) {
         _cleanup_free_ char *x = NULL;
@@ -39,7 +40,7 @@ static void test_specifier_escape_strv(void) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         test_specifier_escape();
         test_specifier_escape_strv();
index 340b5628f9b8ccc79e70fce44b860a02345eedf3..5b0b9547b7c393f959e7a62118b39888d0767ff7 100644 (file)
@@ -144,6 +144,38 @@ static void test_strv_join(void) {
         assert_se(streq(w, ""));
 }
 
+static void test_strv_join_prefix(void) {
+        _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
+
+        p = strv_join_prefix((char **)input_table_multiple, ", ", "foo");
+        assert_se(p);
+        assert_se(streq(p, "fooone, footwo, foothree"));
+
+        q = strv_join_prefix((char **)input_table_multiple, ";", "foo");
+        assert_se(q);
+        assert_se(streq(q, "fooone;footwo;foothree"));
+
+        r = strv_join_prefix((char **)input_table_multiple, NULL, "foo");
+        assert_se(r);
+        assert_se(streq(r, "fooone footwo foothree"));
+
+        s = strv_join_prefix((char **)input_table_one, ", ", "foo");
+        assert_se(s);
+        assert_se(streq(s, "fooone"));
+
+        t = strv_join_prefix((char **)input_table_none, ", ", "foo");
+        assert_se(t);
+        assert_se(streq(t, ""));
+
+        v = strv_join_prefix((char **)input_table_two_empties, ", ", "foo");
+        assert_se(v);
+        assert_se(streq(v, "foo, foo"));
+
+        w = strv_join_prefix((char **)input_table_one_empty, ", ", "foo");
+        assert_se(w);
+        assert_se(streq(w, "foo"));
+}
+
 static void test_strv_unquote(const char *quoted, char **list) {
         _cleanup_strv_free_ char **s;
         _cleanup_free_ char *j;
@@ -252,18 +284,18 @@ static void test_strv_split_nulstr(void) {
 
 static void test_strv_parse_nulstr(void) {
         _cleanup_strv_free_ char **l = NULL;
-        const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
+        const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
 
         l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
         assert_se(l);
         puts("Parse nulstr:");
         strv_print(l);
 
-        assert_se(streq(l[0], "fuck"));
-        assert_se(streq(l[1], "fuck2"));
-        assert_se(streq(l[2], "fuck3"));
+        assert_se(streq(l[0], "hoge"));
+        assert_se(streq(l[1], "hoge2"));
+        assert_se(streq(l[2], "hoge3"));
         assert_se(streq(l[3], ""));
-        assert_se(streq(l[4], "fuck5"));
+        assert_se(streq(l[4], "hoge5"));
         assert_se(streq(l[5], ""));
         assert_se(streq(l[6], "xxx"));
 }
@@ -726,6 +758,7 @@ int main(int argc, char *argv[]) {
         test_strv_find_prefix();
         test_strv_find_startswith();
         test_strv_join();
+        test_strv_join_prefix();
 
         test_strv_unquote("    foo=bar     \"waldo\"    zzz    ", STRV_MAKE("foo=bar", "waldo", "zzz"));
         test_strv_unquote("", STRV_MAKE_EMPTY);
index 3817790233b205083c4519f18e570d46e2df2254..7f288e54ceff72d86e3fa0d6e8e6370d399dd3cc 100644 (file)
@@ -13,6 +13,7 @@
 #include "log.h"
 #include "process-util.h"
 #include "string-util.h"
+#include "tests.h"
 #include "util.h"
 
 int main(int argc, char** argv) {
@@ -21,8 +22,7 @@ int main(int argc, char** argv) {
         const char *p = argv[1] ?: "/tmp";
         char *pattern;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         pattern = strjoina(p, "/systemd-test-XXXXXX");
 
index c068f7a0f0db7fac84b58eb1d08bb5d78f6bd730..1b243d03efb3858f728b98da0aeb98081c3df34c 100644 (file)
@@ -53,9 +53,7 @@ static void test_swap_list(const char *fname) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_mount_points_list(NULL);
         test_mount_points_list("/test-umount/empty.mountinfo");
index 09b0179fa1a070d4c70fb3fd8417877bd0fcae07..cb074aaa4d9e4d2dccb842e0aabd565de414829c 100644 (file)
@@ -39,11 +39,8 @@ static int test_unit_file_get_set(void) {
         assert_se(h);
 
         r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
-
-        if (IN_SET(r, -EPERM, -EACCES)) {
-                log_notice_errno(r, "Skipping test: unit_file_get_list: %m");
-                return EXIT_TEST_SKIP;
-        }
+        if (IN_SET(r, -EPERM, -EACCES))
+                return log_tests_skipped_errno(r, "unit_file_get_list");
 
         log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r,
                        "unit_file_get_list: %m");
@@ -896,14 +893,11 @@ int main(int argc, char *argv[]) {
         _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
         int r;
 
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice_errno(r, "Skipping test: cgroupfs not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         assert_se(runtime_dir = setup_fake_runtime_dir());
 
index 2b00ef8cb7347c19da8b8331f6d8cfeebe3d6a81..157c900276edc58622488042d71f7405e3d917ad 100644 (file)
@@ -205,10 +205,8 @@ static int test_unit_printf(void) {
         assert_se(get_shell(&shell) >= 0);
 
         r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
-        if (MANAGER_SKIP_TEST(r)) {
-                log_notice_errno(r, "Skipping test: manager_new: %m");
-                return EXIT_TEST_SKIP;
-        }
+        if (MANAGER_SKIP_TEST(r))
+                return log_tests_skipped_errno(r, "manager_new");
         assert_se(r == 0);
 
 #define expect(unit, pattern, expected)                                 \
@@ -811,14 +809,11 @@ int main(int argc, char* argv[]) {
         _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
         int r, rc = 0;
 
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice_errno(r, "Skipping test: cgroupfs not available");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         assert_se(runtime_dir = setup_fake_runtime_dir());
 
index 4e349ab927b5302853b130f7138b22e546f0e65e..03378ecf089c1aa0f17b32edb78913c2c36f002b 100644 (file)
@@ -13,20 +13,13 @@ int main(int argc, char *argv[]) {
         Unit *a, *b, *c, *u;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
-
-        if (getuid() != 0) {
-                log_notice("Not running as root, skipping kernel related tests.");
-                return EXIT_TEST_SKIP;
-        }
+        test_setup_logging(LOG_DEBUG);
 
+        if (getuid() != 0)
+                return log_tests_skipped("not root");
         r = enter_cgroup_subroot();
-        if (r == -ENOMEDIUM) {
-                log_notice("cgroupfs not available, skipping tests");
-                return EXIT_TEST_SKIP;
-        }
+        if (r == -ENOMEDIUM)
+                return log_tests_skipped("cgroupfs not available");
 
         assert_se(set_unit_path(get_testdata_dir()) >= 0);
         assert_se(runtime_dir = setup_fake_runtime_dir());
index 2aba3b5a26ca2df3c20b7288d9f268c264638ee2..ab66d5c49d83f5757df32961ac86401b3960b819 100644 (file)
@@ -3,8 +3,8 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "env-util.h"
 #include "log.h"
+#include "tests.h"
 #include "watchdog.h"
 
 int main(int argc, char *argv[]) {
@@ -13,11 +13,9 @@ int main(int argc, char *argv[]) {
         int r;
         bool slow;
 
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
-        r = getenv_bool("SYSTEMD_SLOW_TESTS");
-        slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
+        slow = slow_tests_enabled();
 
         t = slow ? 10 * USEC_PER_SEC : 1 * USEC_PER_SEC;
         count = slow ? 5 : 3;
index 72720dccb8c8f71f07a1fedbe579f175cdb90b17..2d93e65be21aea37ac69e7e9ca13ae321f8c08b3 100644 (file)
@@ -12,6 +12,7 @@
 #include "fs-util.h"
 #include "macro.h"
 #include "string-util.h"
+#include "tests.h"
 #include "xattr-util.h"
 
 static void test_fgetxattrat_fake(void) {
@@ -78,9 +79,7 @@ static void test_getcrtime(void) {
 }
 
 int main(void) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_fgetxattrat_fake();
         test_getcrtime();
index a045eeeec11b65ae378e4352725be91ec3455186..bd03a1dd90aca6b37fa7494c56ec395c2d39e577 100644 (file)
@@ -5,6 +5,7 @@
 #include "log.h"
 #include "macro.h"
 #include "timesyncd-conf.h"
+#include "tests.h"
 
 static void test_manager_parse_string(void) {
         /* Make sure that NTP_SERVERS is configured to something
@@ -25,8 +26,7 @@ static void test_manager_parse_string(void) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         test_manager_parse_string();
 
index b91b212a708fbde28863c2fd367cdff715b291df..e29f706fc09fa207bd96745e4ae33d8a63a89ba1 100644 (file)
@@ -2317,18 +2317,16 @@ static void item_array_free(ItemArray *a) {
         free(a);
 }
 
-static int item_compare(const void *a, const void *b) {
-        const Item *x = a, *y = b;
-
+static int item_compare(const Item *a, const Item *b) {
         /* Make sure that the ownership taking item is put first, so
          * that we first create the node, and then can adjust it */
 
-        if (takes_ownership(x->type) && !takes_ownership(y->type))
+        if (takes_ownership(a->type) && !takes_ownership(b->type))
                 return -1;
-        if (!takes_ownership(x->type) && takes_ownership(y->type))
+        if (!takes_ownership(a->type) && takes_ownership(b->type))
                 return 1;
 
-        return (int) x->type - (int) y->type;
+        return CMP(a->type, b->type);
 }
 
 static bool item_compatible(Item *a, Item *b) {
@@ -2793,7 +2791,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         memcpy(existing->items + existing->count++, &i, sizeof(i));
 
         /* Sort item array, to enforce stable ordering of application */
-        qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
+        typesafe_qsort(existing->items, existing->count, item_compare);
 
         zero(i);
         return 0;
index cb49ade4d8f852b9c0214f5143314bf0d1de13d5..d61826c6600875d10f5ce1e0ee4ca885b1ae240f 100644 (file)
@@ -11,6 +11,7 @@
  *
  * Two character prefixes based on the type of interface:
  *   en â€” Ethernet
+ *   ib â€” InfiniBand
  *   sl â€” serial line IP (slip)
  *   wl â€” wlan
  *   ww â€” wwan
  *   ID_NET_NAME_MAC=wlx0024d7e31130
  *   ID_NET_NAME_PATH=wlp3s0
  *
+ * PCI IB host adapter with 2 ports:
+ *   /sys/devices/pci0000:00/0000:00:03.0/0000:15:00.0/net/ibp21s0f0
+ *   ID_NET_NAME_PATH=ibp21s0f0
+ *   /sys/devices/pci0000:00/0000:00:03.0/0000:15:00.1/net/ibp21s0f1
+ *   ID_NET_NAME_PATH=ibp21s0f1
+ *
  * USB built-in 3G modem:
  *   /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
  *   ID_NET_NAME_MAC=wwx028037ec0200
@@ -211,11 +218,10 @@ out_unref:
 
 /* retrieve on-board index number and label from firmware */
 static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
-        unsigned dev_port = 0;
+        unsigned long idx, dev_port = 0;
+        const char *attr, *port_name;
         size_t l;
         char *s;
-        const char *attr, *port_name;
-        int idx;
 
         /* ACPI _DSM  â€” device specific method for naming a PCI or PCI Express device */
         attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
@@ -239,18 +245,18 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
         /* kernel provided port index for multiple ports on a single PCI function */
         attr = udev_device_get_sysattr_value(dev, "dev_port");
         if (attr)
-                dev_port = strtol(attr, NULL, 10);
+                dev_port = strtoul(attr, NULL, 10);
 
         /* kernel provided front panel port name for multiple port PCI device */
         port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
 
         s = names->pci_onboard;
         l = sizeof(names->pci_onboard);
-        l = strpcpyf(&s, l, "o%d", idx);
+        l = strpcpyf(&s, l, "o%lu", idx);
         if (port_name)
                 l = strpcpyf(&s, l, "n%s", port_name);
         else if (dev_port > 0)
-                l = strpcpyf(&s, l, "d%d", dev_port);
+                l = strpcpyf(&s, l, "d%lu", dev_port);
         if (l == 0)
                 names->pci_onboard[0] = '\0';
 
@@ -284,7 +290,8 @@ static bool is_pci_ari_enabled(struct udev_device *dev) {
 }
 
 static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
-        unsigned domain, bus, slot, func, dev_port = 0, hotplug_slot = 0;
+        unsigned long dev_port = 0;
+        unsigned domain, bus, slot, func, hotplug_slot = 0;
         size_t l;
         char *s;
         const char *attr, *port_name;
@@ -304,8 +311,24 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
 
         /* kernel provided port index for multiple ports on a single PCI function */
         attr = udev_device_get_sysattr_value(dev, "dev_port");
-        if (attr)
-                dev_port = strtol(attr, NULL, 10);
+        if (attr) {
+                dev_port = strtoul(attr, NULL, 10);
+                /* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously
+                 * provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
+                 * which thus stays initialized as 0. */
+                if (dev_port == 0) {
+                        unsigned long type;
+
+                        attr = udev_device_get_sysattr_value(dev, "type");
+                        /* The 'type' attribute always exists. */
+                        type = strtoul(attr, NULL, 10);
+                        if (type == ARPHRD_INFINIBAND) {
+                                attr = udev_device_get_sysattr_value(dev, "dev_id");
+                                if (attr)
+                                        dev_port = strtoul(attr, NULL, 16);
+                        }
+                }
+        }
 
         /* kernel provided front panel port name for multiple port PCI device */
         port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
@@ -321,7 +344,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
         if (port_name)
                 l = strpcpyf(&s, l, "n%s", port_name);
         else if (dev_port > 0)
-                l = strpcpyf(&s, l, "d%u", dev_port);
+                l = strpcpyf(&s, l, "d%lu", dev_port);
         if (l == 0)
                 names->pci_path[0] = '\0';
 
@@ -377,7 +400,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
                 if (port_name)
                         l = strpcpyf(&s, l, "n%s", port_name);
                 else if (dev_port > 0)
-                        l = strpcpyf(&s, l, "d%d", dev_port);
+                        l = strpcpyf(&s, l, "d%lu", dev_port);
                 if (l == 0)
                         names->pci_slot[0] = '\0';
         }
@@ -648,9 +671,26 @@ static int names_ccw(struct  udev_device *dev, struct netnames *names) {
 
 static int names_mac(struct udev_device *dev, struct netnames *names) {
         const char *s;
-        unsigned int i;
+        unsigned long i;
         unsigned int a1, a2, a3, a4, a5, a6;
 
+        /* Some kinds of devices tend to have hardware addresses
+         * that are impossible to use in an iface name.
+         */
+        s = udev_device_get_sysattr_value(dev, "type");
+        if (!s)
+                return EXIT_FAILURE;
+        i = strtoul(s, NULL, 0);
+        switch (i) {
+        /* The persistent part of a hardware address of an InfiniBand NIC
+         * is 8 bytes long. We cannot fit this much in an iface name.
+         */
+        case ARPHRD_INFINIBAND:
+                return -EINVAL;
+        default:
+                break;
+        }
+
         /* check for NET_ADDR_PERM, skip random MAC addresses */
         s = udev_device_get_sysattr_value(dev, "addr_assign_type");
         if (!s)
@@ -698,13 +738,15 @@ static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test)
 static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
         const char *s;
         const char *p;
-        unsigned int i;
+        unsigned long i;
         const char *devtype;
         const char *prefix = "en";
         struct netnames names = {};
         int err;
 
-        /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
+        /* handle only ARPHRD_ETHER, ARPHRD_SLIP
+         * and ARPHRD_INFINIBAND devices
+         */
         s = udev_device_get_sysattr_value(dev, "type");
         if (!s)
                 return EXIT_FAILURE;
@@ -713,6 +755,9 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool
         case ARPHRD_ETHER:
                 prefix = "en";
                 break;
+        case ARPHRD_INFINIBAND:
+                prefix = "ib";
+                break;
         case ARPHRD_SLIP:
                 prefix = "sl";
                 break;
index 68c6b8104ca750e42986724f88c45935cc902d43..3125a18088ef06e0482a93a19e48e2c243a2eead 100644 (file)
@@ -144,7 +144,7 @@ int control_main(int argc, char *argv[], void *userdata) {
                         break;
                 }
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
index 9dbbd1bf95c863c1454fed68cb8a6f169e05cc9f..4eb2897b219556a107abd64971b56e1b23647799 100644 (file)
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <ctype.h>
 #include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
 
-#include "alloc-util.h"
-#include "conf-files.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hwdb-internal.h"
 #include "hwdb-util.h"
-#include "label.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "strbuf.h"
-#include "string-util.h"
-#include "udev.h"
 #include "udevadm.h"
 #include "util.h"
 
-/*
- * Generic udev properties, key/value database based on modalias strings.
- * Uses a Patricia/radix trie to index all matches for efficient lookup.
- */
-
 static const char *arg_test = NULL;
 static const char *arg_root = NULL;
-static const char *arg_hwdb_bin_dir = "/etc/udev";
+static const char *arg_hwdb_bin_dir = NULL;
 static bool arg_update = false;
 static bool arg_strict = false;
 
-static const char * const conf_file_dirs[] = {
-        "/etc/udev/hwdb.d",
-        UDEVLIBEXECDIR "/hwdb.d",
-        NULL
-};
-
-/* in-memory trie objects */
-struct trie {
-        struct trie_node *root;
-        struct strbuf *strings;
-
-        size_t nodes_count;
-        size_t children_count;
-        size_t values_count;
-};
-
-struct trie_node {
-        /* prefix, common part for all children of this node */
-        size_t prefix_off;
-
-        /* sorted array of pointers to children nodes */
-        struct trie_child_entry *children;
-        uint8_t children_count;
-
-        /* sorted array of key/value pairs */
-        struct trie_value_entry *values;
-        size_t values_count;
-};
-
-/* children array item with char (0-255) index */
-struct trie_child_entry {
-        uint8_t c;
-        struct trie_node *child;
-};
-
-/* value array item with key/value pairs */
-struct trie_value_entry {
-        size_t key_off;
-        size_t value_off;
-};
-
-static int trie_children_cmp(const void *v1, const void *v2) {
-        const struct trie_child_entry *n1 = v1;
-        const struct trie_child_entry *n2 = v2;
-
-        return n1->c - n2->c;
-}
-
-static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
-        struct trie_child_entry *child;
-
-        /* extend array, add new entry, sort for bisection */
-        child = reallocarray(node->children, node->children_count + 1, sizeof(struct trie_child_entry));
-        if (!child)
-                return -ENOMEM;
-
-        node->children = child;
-        trie->children_count++;
-        node->children[node->children_count].c = c;
-        node->children[node->children_count].child = node_child;
-        node->children_count++;
-        qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
-        trie->nodes_count++;
-
-        return 0;
-}
-
-static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
-        struct trie_child_entry *child;
-        struct trie_child_entry search;
-
-        search.c = c;
-        child = bsearch_safe(&search,
-                             node->children, node->children_count, sizeof(struct trie_child_entry),
-                             trie_children_cmp);
-        if (child)
-                return child->child;
-        return NULL;
-}
-
-static void trie_node_cleanup(struct trie_node *node) {
-        size_t i;
-
-        if (!node)
-                return;
-
-        for (i = 0; i < node->children_count; i++)
-                trie_node_cleanup(node->children[i].child);
-        free(node->children);
-        free(node->values);
-        free(node);
-}
-
-static void trie_free(struct trie *trie) {
-        if (!trie)
-                return;
-
-        trie_node_cleanup(trie->root);
-        strbuf_cleanup(trie->strings);
-        free(trie);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free);
-
-static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
-        const struct trie_value_entry *val1 = v1;
-        const struct trie_value_entry *val2 = v2;
-        struct trie *trie = arg;
-
-        return strcmp(trie->strings->buf + val1->key_off,
-                      trie->strings->buf + val2->key_off);
-}
-
-static int trie_node_add_value(struct trie *trie, struct trie_node *node,
-                          const char *key, const char *value) {
-        ssize_t k, v;
-        struct trie_value_entry *val;
-
-        k = strbuf_add_string(trie->strings, key, strlen(key));
-        if (k < 0)
-                return k;
-        v = strbuf_add_string(trie->strings, value, strlen(value));
-        if (v < 0)
-                return v;
-
-        if (node->values_count) {
-                struct trie_value_entry search = {
-                        .key_off = k,
-                        .value_off = v,
-                };
-
-                val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
-                if (val) {
-                        /* replace existing earlier key with new value */
-                        val->value_off = v;
-                        return 0;
-                }
-        }
-
-        /* extend array, add new entry, sort for bisection */
-        val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry));
-        if (!val)
-                return -ENOMEM;
-        trie->values_count++;
-        node->values = val;
-        node->values[node->values_count].key_off = k;
-        node->values[node->values_count].value_off = v;
-        node->values_count++;
-        qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
-        return 0;
-}
-
-static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
-                       const char *key, const char *value) {
-        size_t i = 0;
-        int err = 0;
-
-        for (;;) {
-                size_t p;
-                uint8_t c;
-                struct trie_node *child;
-
-                for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
-                        _cleanup_free_ char *s = NULL;
-                        ssize_t off;
-                        _cleanup_free_ struct trie_node *new_child = NULL;
-
-                        if (c == search[i + p])
-                                continue;
-
-                        /* split node */
-                        new_child = new0(struct trie_node, 1);
-                        if (!new_child)
-                                return -ENOMEM;
-
-                        /* move values from parent to child */
-                        new_child->prefix_off = node->prefix_off + p+1;
-                        new_child->children = node->children;
-                        new_child->children_count = node->children_count;
-                        new_child->values = node->values;
-                        new_child->values_count = node->values_count;
-
-                        /* update parent; use strdup() because the source gets realloc()d */
-                        s = strndup(trie->strings->buf + node->prefix_off, p);
-                        if (!s)
-                                return -ENOMEM;
-
-                        off = strbuf_add_string(trie->strings, s, p);
-                        if (off < 0)
-                                return off;
-
-                        node->prefix_off = off;
-                        node->children = NULL;
-                        node->children_count = 0;
-                        node->values = NULL;
-                        node->values_count = 0;
-                        err = node_add_child(trie, node, new_child, c);
-                        if (err)
-                                return err;
-
-                        new_child = NULL; /* avoid cleanup */
-                        break;
-                }
-                i += p;
-
-                c = search[i];
-                if (c == '\0')
-                        return trie_node_add_value(trie, node, key, value);
-
-                child = node_lookup(node, c);
-                if (!child) {
-                        ssize_t off;
-
-                        /* new child */
-                        child = new0(struct trie_node, 1);
-                        if (!child)
-                                return -ENOMEM;
-
-                        off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
-                        if (off < 0) {
-                                free(child);
-                                return off;
-                        }
-
-                        child->prefix_off = off;
-                        err = node_add_child(trie, node, child, c);
-                        if (err) {
-                                free(child);
-                                return err;
-                        }
-
-                        return trie_node_add_value(trie, child, key, value);
-                }
-
-                node = child;
-                i++;
-        }
-}
-
-struct trie_f {
-        FILE *f;
-        struct trie *trie;
-        uint64_t strings_off;
-
-        uint64_t nodes_count;
-        uint64_t children_count;
-        uint64_t values_count;
-};
-
-/* calculate the storage space for the nodes, children arrays, value arrays */
-static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
-        uint64_t i;
-
-        for (i = 0; i < node->children_count; i++)
-                trie_store_nodes_size(trie, node->children[i].child);
-
-        trie->strings_off += sizeof(struct trie_node_f);
-        for (i = 0; i < node->children_count; i++)
-                trie->strings_off += sizeof(struct trie_child_entry_f);
-        for (i = 0; i < node->values_count; i++)
-                trie->strings_off += sizeof(struct trie_value_entry_f);
-}
-
-static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
-        uint64_t i;
-        struct trie_node_f n = {
-                .prefix_off = htole64(trie->strings_off + node->prefix_off),
-                .children_count = node->children_count,
-                .values_count = htole64(node->values_count),
-        };
-        struct trie_child_entry_f *children = NULL;
-        int64_t node_off;
-
-        if (node->children_count) {
-                children = new0(struct trie_child_entry_f, node->children_count);
-                if (!children)
-                        return -ENOMEM;
-        }
-
-        /* post-order recursion */
-        for (i = 0; i < node->children_count; i++) {
-                int64_t child_off;
-
-                child_off = trie_store_nodes(trie, node->children[i].child);
-                if (child_off < 0) {
-                        free(children);
-                        return child_off;
-                }
-                children[i].c = node->children[i].c;
-                children[i].child_off = htole64(child_off);
-        }
-
-        /* write node */
-        node_off = ftello(trie->f);
-        fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
-        trie->nodes_count++;
-
-        /* append children array */
-        if (node->children_count) {
-                fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
-                trie->children_count += node->children_count;
-                free(children);
-        }
-
-        /* append values array */
-        for (i = 0; i < node->values_count; i++) {
-                struct trie_value_entry_f v = {
-                        .key_off = htole64(trie->strings_off + node->values[i].key_off),
-                        .value_off = htole64(trie->strings_off + node->values[i].value_off),
-                };
-
-                fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f);
-                trie->values_count++;
-        }
-
-        return node_off;
-}
-
-static int trie_store(struct trie *trie, const char *filename) {
-        struct trie_f t = {
-                .trie = trie,
-        };
-        _cleanup_free_ char *filename_tmp = NULL;
-        int64_t pos;
-        int64_t root_off;
-        int64_t size;
-        struct trie_header_f h = {
-                .signature = HWDB_SIG,
-                .tool_version = htole64(atoi(PACKAGE_VERSION)),
-                .header_size = htole64(sizeof(struct trie_header_f)),
-                .node_size = htole64(sizeof(struct trie_node_f)),
-                .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
-                .value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
-        };
-        int err;
-
-        /* calculate size of header, nodes, children entries, value entries */
-        t.strings_off = sizeof(struct trie_header_f);
-        trie_store_nodes_size(&t, trie->root);
-
-        err = fopen_temporary(filename, &t.f, &filename_tmp);
-        if (err < 0)
-                return err;
-        fchmod(fileno(t.f), 0444);
-
-        /* write nodes */
-        if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
-                goto error_fclose;
-        root_off = trie_store_nodes(&t, trie->root);
-        h.nodes_root_off = htole64(root_off);
-        pos = ftello(t.f);
-        h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
-
-        /* write string buffer */
-        fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
-        h.strings_len = htole64(trie->strings->len);
-
-        /* write header */
-        size = ftello(t.f);
-        h.file_size = htole64(size);
-        if (fseeko(t.f, 0, SEEK_SET < 0))
-                goto error_fclose;
-        fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
-
-        if (ferror(t.f))
-                goto error_fclose;
-        if (fflush(t.f) < 0)
-                goto error_fclose;
-        if (fsync(fileno(t.f)) < 0)
-                goto error_fclose;
-        if (rename(filename_tmp, filename) < 0)
-                goto error_fclose;
-
-        /* write succeeded */
-        fclose(t.f);
-
-        log_debug("=== trie on-disk ===");
-        log_debug("size:             %8"PRIi64" bytes", size);
-        log_debug("header:           %8zu bytes", sizeof(struct trie_header_f));
-        log_debug("nodes:            %8"PRIu64" bytes (%8"PRIu64")",
-                  t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
-        log_debug("child pointers:   %8"PRIu64" bytes (%8"PRIu64")",
-                  t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
-        log_debug("value pointers:   %8"PRIu64" bytes (%8"PRIu64")",
-                  t.values_count * sizeof(struct trie_value_entry_f), t.values_count);
-        log_debug("string store:     %8zu bytes", trie->strings->len);
-        log_debug("strings start:    %8"PRIu64, t.strings_off);
-
-        return 0;
-
- error_fclose:
-        err = -errno;
-        fclose(t.f);
-        unlink(filename_tmp);
-        return err;
-}
-
-static int insert_data(struct trie *trie, struct udev_list *match_list,
-                       char *line, const char *filename) {
-        char *value;
-        struct udev_list_entry *entry;
-
-        value = strchr(line, '=');
-        if (!value) {
-                log_error("Error, key/value pair expected but got '%s' in '%s':", line, filename);
-                return -EINVAL;
-        }
-
-        value[0] = '\0';
-        value++;
-
-        /* libudev requires properties to start with a space */
-        while (isblank(line[0]) && isblank(line[1]))
-                line++;
-
-        if (line[0] == '\0' || value[0] == '\0') {
-                log_error("Error, empty key or value '%s' in '%s':", line, filename);
-                return -EINVAL;
-        }
-
-        udev_list_entry_foreach(entry, udev_list_get_entry(match_list))
-                trie_insert(trie, trie->root, udev_list_entry_get_name(entry), line, value);
-
-        return 0;
-}
-
-static int import_file(struct trie *trie, const char *filename) {
-        enum {
-                HW_MATCH,
-                HW_DATA,
-                HW_NONE,
-        } state = HW_NONE;
-        FILE *f;
-        char line[LINE_MAX];
-        struct udev_list match_list;
-        int r = 0, err;
-
-        udev_list_init(NULL, &match_list, false);
-
-        f = fopen(filename, "re");
-        if (f == NULL)
-                return -errno;
-
-        while (fgets(line, sizeof(line), f)) {
-                size_t len;
-                char *pos;
-
-                /* comment line */
-                if (line[0] == '#')
-                        continue;
-
-                /* strip trailing comment */
-                pos = strchr(line, '#');
-                if (pos)
-                        pos[0] = '\0';
-
-                /* strip trailing whitespace */
-                len = strlen(line);
-                while (len > 0 && isspace(line[len-1]))
-                        len--;
-                line[len] = '\0';
-
-                switch (state) {
-                case HW_NONE:
-                        if (len == 0)
-                                break;
-
-                        if (line[0] == ' ') {
-                                log_error("Error, MATCH expected but got '%s' in '%s':", line, filename);
-                                r = -EINVAL;
-                                break;
-                        }
-
-                        /* start of record, first match */
-                        state = HW_MATCH;
-                        udev_list_entry_add(&match_list, line, NULL);
-                        break;
-
-                case HW_MATCH:
-                        if (len == 0) {
-                                log_error("Error, DATA expected but got empty line in '%s':", filename);
-                                r = -EINVAL;
-                                state = HW_NONE;
-                                udev_list_cleanup(&match_list);
-                                break;
-                        }
-
-                        /* another match */
-                        if (line[0] != ' ') {
-                                udev_list_entry_add(&match_list, line, NULL);
-                                break;
-                        }
-
-                        /* first data */
-                        state = HW_DATA;
-                        err = insert_data(trie, &match_list, line, filename);
-                        if (err < 0)
-                                r = err;
-                        break;
-
-                case HW_DATA:
-                        /* end of record */
-                        if (len == 0) {
-                                state = HW_NONE;
-                                udev_list_cleanup(&match_list);
-                                break;
-                        }
-
-                        if (line[0] != ' ') {
-                                log_error("Error, DATA expected but got '%s' in '%s':", line, filename);
-                                r = -EINVAL;
-                                state = HW_NONE;
-                                udev_list_cleanup(&match_list);
-                                break;
-                        }
-
-                        err = insert_data(trie, &match_list, line, filename);
-                        if (err < 0)
-                                r = err;
-                        break;
-                };
-        }
-
-        fclose(f);
-        udev_list_cleanup(&match_list);
-        return r;
-}
-
-static int hwdb_update(void) {
-        _cleanup_(trie_freep) struct trie *trie = NULL;
-        _cleanup_strv_free_ char **files = NULL;
-        _cleanup_free_ char *hwdb_bin = NULL;
-        char **f;
-        int r;
-
-        trie = new0(struct trie, 1);
-        if (!trie)
-                return -ENOMEM;
-
-        /* string store */
-        trie->strings = strbuf_new();
-        if (!trie->strings)
-                return -ENOMEM;
-
-        /* index */
-        trie->root = new0(struct trie_node, 1);
-        if (!trie->root)
-                return -ENOMEM;
-
-        trie->nodes_count++;
-
-        r = conf_files_list_strv(&files, ".hwdb", arg_root, 0, conf_file_dirs);
-        if (r < 0)
-                return log_error_errno(r, "failed to enumerate hwdb files: %m");
-
-        STRV_FOREACH(f, files) {
-                log_debug("Reading file '%s'", *f);
-                r = import_file(trie, *f);
-                if (r < 0 && arg_strict)
-                        return r;
-        }
-
-        strbuf_complete(trie->strings);
-
-        log_debug("=== trie in-memory ===");
-        log_debug("nodes:            %8zu bytes (%8zu)",
-                  trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
-        log_debug("children arrays:  %8zu bytes (%8zu)",
-                  trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
-        log_debug("values arrays:    %8zu bytes (%8zu)",
-                  trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
-        log_debug("strings:          %8zu bytes",
-                  trie->strings->len);
-        log_debug("strings incoming: %8zu bytes (%8zu)",
-                  trie->strings->in_len, trie->strings->in_count);
-        log_debug("strings dedup'ed: %8zu bytes (%8zu)",
-                  trie->strings->dedup_len, trie->strings->dedup_count);
-
-        hwdb_bin = path_join(arg_root, arg_hwdb_bin_dir, "/hwdb.bin");
-        if (!hwdb_bin)
-                return -ENOMEM;
-
-        mkdir_parents_label(hwdb_bin, 0755);
-
-        r = trie_store(trie, hwdb_bin);
-        if (r < 0)
-                log_error_errno(r, "Failed to write database %s: %m", hwdb_bin);
-
-        (void) label_fix(hwdb_bin, 0);
-
-        return r;
-}
-
-static int hwdb_test(void) {
-        _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
-        const char *key, *value;
-        int r;
-
-        r = sd_hwdb_new(&hwdb);
-        if (r < 0)
-                return r;
-
-        SD_HWDB_FOREACH_PROPERTY(hwdb, arg_test, key, value)
-                printf("%s=%s\n", key, value);
-
-        return 0;
-}
-
 static int help(void) {
         printf("%s hwdb [OPTIONS]\n\n"
                "  -h --help            Print this message\n"
@@ -692,7 +65,7 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_root = optarg;
                         break;
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
@@ -707,8 +80,10 @@ static int parse_argv(int argc, char *argv[]) {
 int hwdb_main(int argc, char *argv[], void *userdata) {
         int r;
 
+        log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
+
         r = parse_argv(argc, argv);
-        if (r < 0)
+        if (r <= 0)
                 return r;
 
         if (!arg_update && !arg_test) {
@@ -717,13 +92,13 @@ int hwdb_main(int argc, char *argv[], void *userdata) {
         }
 
         if (arg_update) {
-                r = hwdb_update();
+                r = hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, true);
                 if (r < 0)
                         return r;
         }
 
         if (arg_test)
-                return hwdb_test();
+                return hwdb_query(arg_test);
 
         return 0;
 }
index 23a27d0a28515679a238f07266fea47bbe76511d..92c7cfe6bfdacec73f0a4ebf3bc3b81a90af80f2 100644 (file)
@@ -357,7 +357,7 @@ int info_main(int argc, char *argv[], void *userdata) {
                         export_prefix = optarg;
                         break;
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
index ba6f30f17f2688ad3ea8b256472110049a86784f..8a0db2b89d83721aa3569eeaebe99b1566bdf13e 100644 (file)
@@ -205,7 +205,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
index a172b25adad80fb39b4a9159c6390c3b937ad4c1..7e02275ba4e5fe9a49156bccef8d4ed02b25afd4 100644 (file)
@@ -57,7 +57,7 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_exists = optarg;
                         break;
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case 's':
index ac1a8c2d7da8505c9b67a5edd34ee93faacc179f..940d691dd7d32d0a8b2c025cbf1190a9b6b18362 100644 (file)
@@ -40,7 +40,7 @@ static int parse_argv(int argc, char *argv[]) {
         while ((c = getopt_long(argc, argv, "Vh", options, NULL)) >= 0)
                 switch (c) {
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
index 65e14a86645383d0c763060f0f661e728cc5ae13..462c5818f456c02f990f2f9e35f3fbc554437532 100644 (file)
@@ -62,7 +62,7 @@ static int parse_argv(int argc, char *argv[]) {
                         }
                         break;
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
index 84a977e0942d22e16f605f31fc3f4b9f988df270..e08d342f2908b7b260849153cdf7ffc6cb770b8e 100644 (file)
@@ -232,7 +232,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                 }
 
                 case 'V':
-                        return version();
+                        return print_version();
                 case 'h':
                         return help();
                 case '?':
index 7c6eb3bf4c3832e06c942aca36cb642cd186bc59..64092c55006f0d019bc94558f601c805413f7740 100644 (file)
@@ -68,7 +68,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return help();
 
                 case 'V':
-                        return version();
+                        return print_version();
 
                 case '?':
                         return -EINVAL;
@@ -81,7 +81,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 static int version_main(int argc, char *argv[], void *userdata) {
-        return version();
+        return print_version();
 }
 
 static int help_main(int argc, char *argv[], void *userdata) {
index 7c20e0a8ff878b1718ef7da432e0c2044d7dff03..98f9019a48aaa7d9c7c278ca544792a09be3ebc0 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 #pragma once
 
+#include <stdio.h>
+
 int info_main(int argc, char *argv[], void *userdata);
 int trigger_main(int argc, char *argv[], void *userdata);
 int settle_main(int argc, char *argv[], void *userdata);
@@ -9,3 +11,8 @@ int monitor_main(int argc, char *argv[], void *userdata);
 int hwdb_main(int argc, char *argv[], void *userdata);
 int test_main(int argc, char *argv[], void *userdata);
 int builtin_main(int argc, char *argv[], void *userdata);
+
+static inline int print_version(void) {
+        puts(PACKAGE_VERSION);
+        return 0;
+}
index 616ffb972892a716c03fe9330d6c78f04a324068..9750ff22b944a2409e22dbbba976fdc5a02573ad 100644 (file)
@@ -211,16 +211,20 @@ endif
 ############################################################
 
 rule_syntax_check_py = find_program('rule-syntax-check.py')
-test('rule-syntax-check',
-     rule_syntax_check_py,
-     args : all_rules)
+if want_tests != 'false'
+        test('rule-syntax-check',
+             rule_syntax_check_py,
+             args : all_rules)
+endif
 
 ############################################################
 
 if conf.get('HAVE_SYSV_COMPAT') == 1
         sysv_generator_test_py = find_program('sysv-generator-test.py')
-        test('sysv-generator-test',
-             sysv_generator_test_py)
+        if want_tests != 'false'
+                test('sysv-generator-test',
+                     sysv_generator_test_py)
+        endif
 endif
 
 ############################################################
@@ -231,21 +235,25 @@ custom_target(
         'sys',
         command : [sys_script_py, meson.current_build_dir()],
         output : 'sys',
-        build_by_default : true)
+        build_by_default : want_tests != 'false')
 
 if perl.found()
         udev_test_pl = find_program('udev-test.pl')
-        test('udev-test',
-             udev_test_pl)
+        if want_tests != 'false'
+                test('udev-test',
+                     udev_test_pl)
+        endif
 else
         message('Skipping udev-test because perl is not available')
 endif
 
 if conf.get('ENABLE_HWDB') == 1
         hwdb_test_sh = find_program('hwdb-test.sh')
-        test('hwdb-test',
-             hwdb_test_sh,
-             timeout : 90)
+        if want_tests != 'false'
+                test('hwdb-test',
+                     hwdb_test_sh,
+                     timeout : 90)
+        endif
 endif
 
 subdir('fuzz-regressions')
index 72e6d7686fc794ef7df2616a1b5d51b960823ef5..5efc5483b8880caa8d2e2e725bcca6c728ae7dc7 100644 (file)
@@ -10,6 +10,7 @@ ExecStart=test -d /var/lib/test-dynamicuser-migrate
 ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
 ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
 ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
 
 Type=oneshot
 DynamicUser=no
index edb0be7ef80832f56f7b7fc0802b95ac204ba6d6..c72302ffd598fe149de72a6e9c79c33ef34628eb 100644 (file)
@@ -18,6 +18,7 @@ ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
 ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
 ExecStart=touch /var/lib/private/test-dynamicuser-migrate/yay
 ExecStart=touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
 
 Type=oneshot
 DynamicUser=yes
index f459f3c1eb9a7af7866b98f455eeb0ad410e3d9a..2fb7b8660bb4c30df408b8635bcc4ccbdac2bcdc 100644 (file)
@@ -10,6 +10,7 @@ ExecStart=test -f /var/lib/waldo/yay
 ExecStart=test -f /var/lib/quux/pief/yayyay
 ExecStart=test -f /var/lib/private/waldo/yay
 ExecStart=test -f /var/lib/private/quux/pief/yayyay
+ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/waldo:%S/quux/pief"'
 
 # Make sure that /var/lib/private/waldo is really the only writable directory besides the obvious candidates
 ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
index 480f904155c98f2681e254af6db2f1c4211f77b4..85ae5161c4aab71a9f6e90f06048ba43a8ea288b 100644 (file)
@@ -3,6 +3,7 @@ Description=Test for RuntimeDirectoryMode
 
 [Service]
 ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a %t/test-exec_runtimedirectory-mode); test "$$mode" = "750"'
+ExecStart=/bin/sh -x -c 'test "$$RUNTIME_DIRECTORY" = "%t/test-exec_runtimedirectory-mode"'
 Type=oneshot
 RuntimeDirectory=test-exec_runtimedirectory-mode
 RuntimeDirectoryMode=0750
index 6a4383110f6567a3f47cac70ffc0a22c61109aae..a33044d23cbe26ab8871df7257f60aac49f58cd4 100644 (file)
@@ -4,6 +4,7 @@ Description=Test for RuntimeDirectory
 [Service]
 ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory'
 ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory2/hogehoge'
+ExecStart=/bin/sh -x -c 'test "$$RUNTIME_DIRECTORY" = "%t/test-exec_runtimedirectory:%t/test-exec_runtimedirectory2/hogehoge"'
 Type=oneshot
 RuntimeDirectory=test-exec_runtimedirectory
 RuntimeDirectory=./test-exec_runtimedirectory2///./hogehoge/.
index 438ecbb288b8f235a2fcc02788088275dae16b96..f1646b3bcffd05091386b307b59a23d8f25ad136 100644 (file)
@@ -330,7 +330,8 @@ create_asan_wrapper() {
 set -x
 
 DEFAULT_ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
-DEFAULT_ENVIRONMENT=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS
+DEFAULT_UBSAN_OPTIONS=print_stacktrace=1:print_summary=1
+DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
 
 mount -t proc proc /proc
 mount -t sysfs sysfs /sys
@@ -353,7 +354,7 @@ JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
 mkdir -p "\$JOURNALD_CONF_DIR"
 printf "[Service]\nEnvironment=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd-journald.asan.log\n" >"\$JOURNALD_CONF_DIR/env.conf"
 
-export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log
+export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
 exec  $ROOTLIBDIR/systemd "\$@"
 EOF
 
@@ -504,9 +505,8 @@ install_execs() {
     export PKG_CONFIG_PATH=$BUILD_DIR/src/core/
     systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd)
     systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd)
-    egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
-         | while read i; do
-         i=${i##Exec*=}; i=${i##[@+\!-]}; i=${i##\!}
+    sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
+         | sort -u | while read i; do
          # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
          inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ]
      done
index 70f7172ae906019e1863bd4698e950fa55d78861..e2b260398c5dde9937679d623e9b10304166b644 100755 (executable)
@@ -18,10 +18,10 @@ unitpath="${DESTDIR:-}${unitdir}/${unit}"
 
 case "$target" in
         */)
-                mkdir -p -m 0755 "$dir"
+                mkdir -vp -m 0755 "$dir"
                 ;;
         *)
-                mkdir -p -m 0755 "$(basename "$dir")"
+                mkdir -vp -m 0755 "$(dirname "$dir")"
                 ;;
 esac
 
index 384be59481d72e2f8ce9ce2a2c831e6ae00f31a7..b02bbcd61b7004a481b4b56f4aea278bb8cb8e3c 100644 (file)
@@ -12,7 +12,7 @@ Description=Create Volatile Files and Directories
 Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
-After=local-fs.target systemd-sysusers.service
+After=local-fs.target systemd-sysusers.service systemd-journald.service
 Before=sysinit.target shutdown.target
 RefuseManualStop=yes