]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #17877 from yuwata/missing-syscall-sort
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 10 Dec 2020 03:42:35 +0000 (12:42 +0900)
committerGitHub <noreply@github.com>
Thu, 10 Dec 2020 03:42:35 +0000 (12:42 +0900)
missing: sort architectures in missing_syscall.h

34 files changed:
.mkosi/mkosi.arch
.mkosi/mkosi.debian
.mkosi/mkosi.fedora
.mkosi/mkosi.opensuse
.mkosi/mkosi.ubuntu
hwdb.d/60-keyboard.hwdb
man/systemd-resolved.service.xml
man/systemd.automount.xml
man/systemd.swap.xml
meson.build
src/basic/async.h
src/basic/hashmap.c
src/basic/log.c
src/basic/log.h
src/basic/set.h
src/basic/virt.c
src/core/cgroup.c
src/core/manager.c
src/core/manager.h
src/libsystemd/sd-device/device-private.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-sd-device.c
src/login/logind-button.c
src/shared/mount-util.h
src/shared/qrcode-util.c
src/shared/qrcode-util.h
src/test/meson.build
src/test/test-dlopen-so.c [new file with mode: 0644]
src/test/test-set.c
src/udev/udev-node.c
src/udev/udevd.c
test/test-functions
test/units/testsuite-55.sh
units/systemd-networkd.service.in

index c50ee4923c2b466137394504c8f03cf75c2abc29..81ce68ccd980801f86b7d3ab686978ebca7c22d0 100644 (file)
@@ -54,5 +54,10 @@ BuildPackages=
         zstd
 
 Packages=
+        gdb
         libidn2
         qrencode
+        strace
+
+[Host]
+QemuHeadless=yes
index ba9077eaa2414d31a8d8b3436c70099f1e8a1f5d..0f47bb5ad1d2c5fec9f2a57d269f39f37edc573e 100644 (file)
@@ -62,6 +62,11 @@ BuildPackages=
         zstd
 
 Packages=
+        gdb
+        libidn2-0
         libqrencode4
         locales
-        libidn2-0
+        strace
+
+[Host]
+QemuHeadless=yes
index a3e68acdfa35a20b1f3ded3588b75dfe2b5da9eb..e113fd92a806f56c9e3163dd8847adcfbc8d9985 100644 (file)
@@ -72,11 +72,16 @@ BuildPackages=
         zstd
 
 Packages=
+        gdb
         # libfido2 + libzstd can be dropped once the Fedora RPM gets a dependency on them
         libfido2
         libzstd
         # procps-ng provides a set of useful utilies (ps, free, etc)
         procps-ng
+        strace
 
 BuildDirectory=mkosi.builddir
 Cache=mkosi.cache
+
+[Host]
+QemuHeadless=yes
index 9f3abbc74b2df72b6194db905261d987862176c2..0dcd0c436d1c39394f5a8ec3729b8bc64c3d1dfb 100644 (file)
@@ -62,6 +62,7 @@ BuildPackages=
         timezone
 
 Packages=
+        gdb
         # brought in via meson->python3
         libp11-kit0
         # --bootable=no
@@ -75,4 +76,8 @@ Packages=
         libqrencode4
         libseccomp2
         pam
+        strace
         util-linux
+
+[Host]
+QemuHeadless=yes
index ff81536956153f7ee0a733a6d87e4717c47fafe2..47a2b9c3f8e8ddcb16bfc7142de2218902caf1c0 100644 (file)
@@ -66,6 +66,11 @@ BuildPackages=
         zstd
 
 Packages=
+        gdb
+        libidn2-0
         libqrencode4
         locales
-        libidn2-0
+        strace
+
+[Host]
+QemuHeadless=yes
index 37955a316d6fd04af97f85668b26f3b558ad1353..9346248b1c0be3c412265d06ad4fd6edf49fb5e5 100644 (file)
@@ -1276,6 +1276,16 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*A10SC*:*
  KEYBOARD_KEY_f1=f20
  KEYBOARD_KEY_f2=f21
 
+# MSI Modern series
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-StarInternational*:pnModern*:*
+ KEYBOARD_KEY_f1=f20                                    # Fn+F5 micmute
+ KEYBOARD_KEY_76=f21                                    # Fn+F4 touchpad, becomes meta+ctrl+toggle
+ KEYBOARD_KEY_91=prog1                                  # Fn+F7 Creation Center, sometime F7
+ KEYBOARD_KEY_f2=prog2                                  # Fn+F12 screen rotation
+ KEYBOARD_KEY_97=unknown                                # lid close
+ KEYBOARD_KEY_98=unknown                                # lid open
+                                                        #Fn+PrntScr sends meta+shif+s
+
 ###########################################################
 # MSI
 ###########################################################
index 12aefd5a892f5296dc8fbc66f134ae587a9ed7b8..93ffca6bfaa76d1a3caee40dc34294e7fa2ac669 100644 (file)
@@ -87,7 +87,7 @@
   <refsect1>
     <title>Synthetic Records</title>
 
-    <para><command>systemd-resolved</command> synthetizes DNS resource records (RRs) for the following
+    <para><command>systemd-resolved</command> synthesizes DNS resource records (RRs) for the following
     cases:</para>
 
     <itemizedlist>
 
       <listitem><para>Single-label names are resolved using LLMNR on all local interfaces where LLMNR is
       enabled. Lookups for IPv4 addresses are only sent via LLMNR on IPv4, and lookups for IPv6 addresses are
-      only sent via LLMNR on IPv6. Note that lookups for single-label synthetized names are not routed to
+      only sent via LLMNR on IPv6. Note that lookups for single-label synthesized names are not routed to
       LLMNR, MulticastDNS or unicast DNS.</para></listitem>
 
-      <listitem><para>Queries for the address records (A and AAAA) of single-label non-synthetized names are
+      <listitem><para>Queries for the address records (A and AAAA) of single-label non-synthesized names are
       resolved via unicast DNS using search domains. For any interface which defines search domains, such
       look-ups are routed to that interface, suffixed with each of the search domains defined on that
       interface in turn. When global search domains are defined, such look-ups are routed to all interfaces,
     determined based on the configured DNS domains for a link: if there's a route-only domain other than
     <literal>~.</literal>, it defaults to false, otherwise to true.</para>
 
-    <para>Effectively this means: in order to support single-label non-synthetized names, define appropriate
+    <para>Effectively this means: in order to support single-label non-synthesized names, define appropriate
     search domains. In order to preferably route all DNS queries not explicitly matched by routing domain
     configuration to a specific link, configure a <literal>~.</literal> route-only domain on it. This will
     ensure that other links will not be considered for these queries (unless they too carry such a routing
index a592fd3af2f6a4d73af1ff378fa696a4eacc622b..a6bc81e216b50f292ee8cf7ffc3fef787caacfa0 100644 (file)
     for mount dependencies here. For example, you should not set
     <varname>After=network-online.target</varname> or similar on network
     filesystems. Doing so may result in an ordering cycle.</para>
+
+    <para>Note that automount support on Linux is privileged, automount units are hence only available in the
+    system service manager (and root's user service manager), but not in unprivileged user's service
+    manager.</para>
   </refsect1>
 
   <refsect1>
index 3e41d6f0bfed7ffc30617990ed5cdf9b2548772c..2a867f92e9777fc4cc236faaac06e08c0fa215cb 100644 (file)
@@ -59,6 +59,9 @@
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that swap
     units cannot be templated, nor is possible to add multiple names to a swap unit by creating additional symlinks to
     it.</para>
+
+    <para>Note that swap support on Linux is privileged, swap units are hence only available in the system
+    service manager (and root's user service manager), but not in unprivileged user's service manager.</para>
   </refsect1>
 
   <refsect1>
index 5d9413a5bbcdc59d7d2db4e023504aec967c4321..513b841ac540bd4b010e7ab342e8dd1ddb305da7 100644 (file)
@@ -1117,6 +1117,7 @@ conf.set10('HAVE_LIBIPTC', have)
 want_qrencode = get_option('qrencode')
 if want_qrencode != 'false' and not skip_deps
         libqrencode = dependency('libqrencode',
+                                 version : '>= 4',
                                  required : want_qrencode == 'true')
         have = libqrencode.found()
 else
index 9ada32c9948fcfe3294dc6b79239220be8ade614..e0bbaa5658319dd07ff89ddad98384e4a763412d 100644 (file)
@@ -1,7 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <sys/types.h>
+
+#include "macro.h"
+
 int asynchronous_job(void* (*func)(void *p), void *arg);
 
 int asynchronous_sync(pid_t *ret_pid);
 int asynchronous_close(int fd);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(int, asynchronous_close);
index dd1b18c87824d5755c23fee6a9022d639aac96f4..e38e5805300e0a8adaca00fa30bad94974d032ba 100644 (file)
@@ -1976,3 +1976,38 @@ IteratedCache* iterated_cache_free(IteratedCache *cache) {
 
         return mfree(cache);
 }
+
+int set_strjoin(Set *s, const char *separator, char **ret) {
+        size_t separator_len, allocated = 0, len = 0;
+        _cleanup_free_ char *str = NULL;
+        const char *value;
+        bool first = true;
+
+        assert(ret);
+
+        separator_len = strlen_ptr(separator);
+
+        SET_FOREACH(value, s) {
+                size_t l = strlen_ptr(value);
+
+                if (l == 0)
+                        continue;
+
+                if (!GREEDY_REALLOC(str, allocated, len + l + (first ? 0 : separator_len) + 1))
+                        return -ENOMEM;
+
+                if (separator_len > 0 && !first) {
+                        memcpy(str + len, separator, separator_len);
+                        len += separator_len;
+                }
+
+                memcpy(str + len, value, l);
+                len += l;
+                first = false;
+        }
+        if (str)
+                str[len] = '\0';
+
+        *ret = TAKE_PTR(str);
+        return 0;
+}
index d4054cf46a8e87728d43c0f36ab3643439144d34..dd9c7db18ba7bda18570e7cd5183f073a57a9aa0 100644 (file)
@@ -51,7 +51,7 @@ static int journal_fd = -1;
 
 static bool syslog_is_stream = false;
 
-static bool show_color = false;
+static int show_color = -1; /* tristate */
 static bool show_location = false;
 static bool show_time = false;
 static bool show_tid = false;
@@ -387,11 +387,10 @@ static int write_to_console(
                 iovec[n++] = IOVEC_MAKE_STRING(prefix);
         }
 
-        if (show_time) {
-                if (format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) {
-                        iovec[n++] = IOVEC_MAKE_STRING(header_time);
-                        iovec[n++] = IOVEC_MAKE_STRING(" ");
-                }
+        if (show_time &&
+            format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) {
+                iovec[n++] = IOVEC_MAKE_STRING(header_time);
+                iovec[n++] = IOVEC_MAKE_STRING(" ");
         }
 
         if (show_tid) {
@@ -399,12 +398,12 @@ static int write_to_console(
                 iovec[n++] = IOVEC_MAKE_STRING(tid_string);
         }
 
-        if (show_color)
+        if (log_get_show_color())
                 get_log_colors(LOG_PRI(level), &on, &off, NULL);
 
         if (show_location) {
                 const char *lon = "", *loff = "";
-                if (show_color) {
+                if (log_get_show_color()) {
                         lon = ANSI_HIGHLIGHT_YELLOW4;
                         loff = ANSI_NORMAL;
                 }
@@ -1222,7 +1221,7 @@ void log_show_color(bool b) {
 }
 
 bool log_get_show_color(void) {
-        return show_color;
+        return show_color > 0; /* Defaults to false. */
 }
 
 void log_show_location(bool b) {
@@ -1485,7 +1484,9 @@ void log_setup_service(void) {
 void log_setup_cli(void) {
         /* Sets up logging the way it is most appropriate for running a program as a CLI utility. */
 
-        log_show_color(true);
+        log_set_target(LOG_TARGET_AUTO);
         log_parse_environment_cli();
         (void) log_open();
+        if (log_on_console() && show_color < 0)
+                log_show_color(true);
 }
index a2aae16df29ef8a495da6b22fb0d9ecef1c81cff..6c5e42a0e43e214d3a54d2d768ac5e106945283f 100644 (file)
@@ -44,10 +44,17 @@ typedef enum LogTarget{
 #define ERRNO_VALUE(val)                    (abs(val) & 255)
 
 void log_set_target(LogTarget target);
+
 void log_set_max_level_realm(LogRealm realm, int level);
+
 #define log_set_max_level(level)                \
         log_set_max_level_realm(LOG_REALM, (level))
 
+static inline void log_set_max_level_all_realms(int level) {
+        for (LogRealm realm = 0; realm < _LOG_REALM_MAX; realm++)
+                log_set_max_level_realm(realm, level);
+}
+
 void log_set_facility(int facility);
 
 int log_set_target_from_string(const char *e);
index 20abc8f0dcf1866f9345a552134af664bcd723ce..2b06c39cbe5647c4d8b2441443f6d8f1bfe145f1 100644 (file)
@@ -150,3 +150,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
 
 #define _cleanup_set_free_ _cleanup_(set_freep)
 #define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_strjoin(Set *s, const char *separator, char **ret);
index 7d78a402b33bdae7c8dce168b609b31397165c1e..33d7106c0ea2a36e22bf801e32c1f6ce754d3a3a 100644 (file)
@@ -517,7 +517,7 @@ int detect_container(void) {
                  */
                 e = getenv("container");
                 if (!e)
-                        goto check_sched;
+                        goto none;
                 if (isempty(e)) {
                         r = VIRTUALIZATION_NONE;
                         goto finish;
@@ -545,24 +545,7 @@ int detect_container(void) {
         if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */
                 log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m");
 
-        /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. If the PID
-         * shown there is not 1, we know we are in a PID namespace and hence a container. */
- check_sched:
-        r = read_one_line_file("/proc/1/sched", &m);
-        if (r >= 0) {
-                const char *t;
-
-                t = strrchr(m, '(');
-                if (!t)
-                        return -EIO;
-
-                if (!startswith(t, "(1,")) {
-                        r = VIRTUALIZATION_CONTAINER_OTHER;
-                        goto finish;
-                }
-        } else if (r != -ENOENT)
-                return r;
-
+none:
         /* If that didn't work, give up, assume no container manager. */
         r = VIRTUALIZATION_NONE;
         goto finish;
index b9d84dcca9356644c661b8f4f70d16fa3eec9588..cebead5eb5199394f4e97a1d38cefc7e85d4704d 100644 (file)
@@ -1244,6 +1244,11 @@ static void cgroup_context_apply(
                         xsprintf(buf, "%" PRIu64 "\n", weight);
                         (void) set_attribute_and_warn(u, "blkio", "blkio.weight", buf);
 
+                        /* FIXME: drop this when distro kernels properly support BFQ through "blkio.weight"
+                         * See also: https://github.com/systemd/systemd/pull/13335 */
+                        xsprintf(buf, "%" PRIu64 "\n", weight);
+                        (void) set_attribute_and_warn(u, "blkio", "blkio.bfq.weight", buf);
+
                         if (has_io) {
                                 CGroupIODeviceWeight *w;
 
@@ -1831,6 +1836,10 @@ int unit_pick_cgroup_path(Unit *u) {
         return 0;
 }
 
+static int cg_v1_errno_to_log_level(int r) {
+        return r == -EROFS ? LOG_DEBUG : LOG_WARNING;
+}
+
 static int unit_update_cgroup(
                 Unit *u,
                 CGroupMask target_mask,
@@ -1888,16 +1897,30 @@ static int unit_update_cgroup(
          * We perform migration also with whole slices for cases when users don't care about leave
          * granularity. Since delegated_mask is subset of target mask, we won't trim slice subtree containing
          * delegated units.
+         *
+         * If we're in an nspawn container and using legacy cgroups, the controller hierarchies are mounted
+         * read-only into the container. We skip migration/trim in this scenario since it would fail
+         * regardless with noisy "Read-only filesystem" warnings.
          */
         if (cg_all_unified() == 0) {
                 r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u);
                 if (r < 0)
-                        log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", u->cgroup_path);
+                        log_unit_full_errno(
+                                u,
+                                cg_v1_errno_to_log_level(r),
+                                r,
+                                "Failed to migrate controller cgroups from %s, ignoring: %m",
+                                u->cgroup_path);
 
                 is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
                 r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice);
                 if (r < 0)
-                        log_unit_warning_errno(u, r, "Failed to delete controller cgroups %s, ignoring: %m", u->cgroup_path);
+                        log_unit_full_errno(
+                                u,
+                                cg_v1_errno_to_log_level(r),
+                                r,
+                                "Failed to delete controller cgroups %s, ignoring: %m",
+                                u->cgroup_path);
         }
 
         /* Set attributes */
index 1f1450b97c171b8dc31e1aca13d5cce0d6aef116..4b215a617665663f8a9eadc298b401c459341fd6 100644 (file)
@@ -2937,8 +2937,10 @@ int manager_loop(Manager *m) {
                 usec_t wait_usec, watchdog_usec;
 
                 watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
-                if (timestamp_is_set(watchdog_usec))
+                if (m->runtime_watchdog_running)
                         (void) watchdog_ping();
+                else if (timestamp_is_set(watchdog_usec))
+                        manager_retry_runtime_watchdog(m);
 
                 if (!ratelimit_below(&rl)) {
                         /* Yay, something is going seriously wrong, pause a little */
@@ -3408,14 +3410,18 @@ void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
 
         if (t == WATCHDOG_RUNTIME)
                 if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
-                        if (timestamp_is_set(timeout))
+                        if (timestamp_is_set(timeout)) {
                                 r = watchdog_set_timeout(&timeout);
-                        else
+
+                                if (r >= 0)
+                                        m->runtime_watchdog_running = true;
+                        } else {
                                 watchdog_close(true);
+                                m->runtime_watchdog_running = false;
+                        }
                 }
 
-        if (r >= 0)
-                m->watchdog[t] = timeout;
+        m->watchdog[t] = timeout;
 }
 
 int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
@@ -3433,18 +3439,36 @@ int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
                 usec_t *p;
 
                 p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
-                if (timestamp_is_set(*p))
+                if (timestamp_is_set(*p)) {
                         r = watchdog_set_timeout(p);
-                else
+
+                        if (r >= 0)
+                                m->runtime_watchdog_running = true;
+                } else {
                         watchdog_close(true);
+                        m->runtime_watchdog_running = false;
+                }
         }
 
-        if (r >= 0)
-                m->watchdog_overridden[t] = timeout;
+        m->watchdog_overridden[t] = timeout;
 
         return 0;
 }
 
+void manager_retry_runtime_watchdog(Manager *m) {
+        int r = 0;
+
+        assert(m);
+
+        if (timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME]))
+                r = watchdog_set_timeout(&m->watchdog_overridden[WATCHDOG_RUNTIME]);
+        else
+                r = watchdog_set_timeout(&m->watchdog[WATCHDOG_RUNTIME]);
+
+        if (r >= 0)
+                m->runtime_watchdog_running = true;
+}
+
 static void manager_deserialize_uid_refs_one_internal(
                 Manager *m,
                 Hashmap** uid_refs,
index d22c801da8d818502921e502e3d112515540b4c8..19df889dd89a379df271fb95a4fb4560e7a3a01e 100644 (file)
@@ -241,6 +241,8 @@ struct Manager {
         usec_t watchdog[_WATCHDOG_TYPE_MAX];
         usec_t watchdog_overridden[_WATCHDOG_TYPE_MAX];
 
+        bool runtime_watchdog_running; /* Whether the runtime HW watchdog was started, so we know if we still need to get the real timeout from the hardware */
+
         dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX];
 
         /* Data specific to the device subsystem */
@@ -562,6 +564,7 @@ ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);
 usec_t manager_get_watchdog(Manager *m, WatchdogType t);
 void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
 int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout);
+void manager_retry_runtime_watchdog(Manager *m);
 
 const char* oom_policy_to_string(OOMPolicy i) _const_;
 OOMPolicy oom_policy_from_string(const char *s) _pure_;
index 2801ebdcbe32080a929d574d562ac3b9d2777527..9070dfbdd1144f2dcf889aa415391667e2ae7a64 100644 (file)
@@ -319,7 +319,10 @@ static int device_amend(sd_device *device, const char *key, const char *value) {
                 for (const char *p = value;;) {
                         _cleanup_free_ char *word = NULL;
 
-                        r = extract_first_word(&p, &word, NULL, 0);
+                        /* udev rules may set escaped strings, and sd-device does not modify the input
+                         * strings. So, it is also necessary to keep the strings received through
+                         * sd-device-monitor. */
+                        r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
                         if (r < 0)
                                 return r;
                         if (r == 0)
index d06f90ce1d881348499b28cf7bb0cf17a584d753..005801e1a69bb7bd9a6e2dd2d34682d2d5e344bc 100644 (file)
@@ -1518,30 +1518,6 @@ _public_ const char *sd_device_get_devlink_next(sd_device *device) {
         return v;
 }
 
-static char *join_string_set(Set *s) {
-        size_t ret_allocated = 0, ret_len;
-        _cleanup_free_ char *ret = NULL;
-        const char *tag;
-
-        if (!GREEDY_REALLOC(ret, ret_allocated, 2))
-                return NULL;
-
-        strcpy(ret, ":");
-        ret_len = 1;
-
-        SET_FOREACH(tag, s) {
-                char *e;
-
-                if (!GREEDY_REALLOC(ret, ret_allocated, ret_len + strlen(tag) + 2))
-                        return NULL;
-
-                e = stpcpy(stpcpy(ret + ret_len, tag), ":");
-                ret_len = e - ret;
-        }
-
-        return TAKE_PTR(ret);
-}
-
 int device_properties_prepare(sd_device *device) {
         int r;
 
@@ -1557,46 +1533,39 @@ int device_properties_prepare(sd_device *device) {
 
         if (device->property_devlinks_outdated) {
                 _cleanup_free_ char *devlinks = NULL;
-                size_t devlinks_allocated = 0, devlinks_len = 0;
-                const char *devlink;
-
-                for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
-                        char *e;
 
-                        if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
-                                return -ENOMEM;
-                        if (devlinks_len > 0)
-                                stpcpy(devlinks + devlinks_len++, " ");
-                        e = stpcpy(devlinks + devlinks_len, devlink);
-                        devlinks_len = e - devlinks;
-                }
-
-                r = device_add_property_internal(device, "DEVLINKS", devlinks);
+                r = set_strjoin(device->devlinks, " ", &devlinks);
                 if (r < 0)
                         return r;
 
+                if (!isempty(devlinks)) {
+                        r = device_add_property_internal(device, "DEVLINKS", devlinks);
+                        if (r < 0)
+                                return r;
+                }
+
                 device->property_devlinks_outdated = false;
         }
 
         if (device->property_tags_outdated) {
                 _cleanup_free_ char *tags = NULL;
 
-                tags = join_string_set(device->all_tags);
-                if (!tags)
-                        return -ENOMEM;
+                r = set_strjoin(device->all_tags, ":", &tags);
+                if (r < 0)
+                        return r;
 
-                if (!streq(tags, ":")) {
+                if (!isempty(tags)) {
                         r = device_add_property_internal(device, "TAGS", tags);
                         if (r < 0)
                                 return r;
                 }
 
-                free(tags);
-                tags = join_string_set(device->current_tags);
-                if (!tags)
-                        return -ENOMEM;
+                tags = mfree(tags);
+                r = set_strjoin(device->current_tags, ":", &tags);
+                if (r < 0)
+                        return r;
 
-                if (!streq(tags, ":")) {
+                if (!isempty(tags)) {
                         r = device_add_property_internal(device, "CURRENT_TAGS", tags);
                         if (r < 0)
                                 return r;
index 9f48d2bf1e8512aaa1cf6e41bd8d8d850ef98ccc..fd30d1a1d023ad3b741086f7e3f2125724e5ed85 100644 (file)
@@ -1,9 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "device-enumerator-private.h"
+#include "device-internal.h"
 #include "device-private.h"
 #include "device-util.h"
 #include "hashmap.h"
+#include "nulstr-util.h"
 #include "string-util.h"
 #include "tests.h"
 #include "time-util.h"
@@ -161,6 +163,47 @@ static void test_sd_device_enumerator_filter_subsystem(void) {
         assert_se(n_new_dev <= 10);
 }
 
+static void test_sd_device_new_from_nulstr(void) {
+        const char *devlinks =
+                "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
+                "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0"
+                "/dev/disk/by-label/Arch\\x20Linux\0"
+                "/dev/disk/by-uuid/a07b87e5-4af5-4a59-bde9-yyyyyyyyyyyy\0"
+                "/dev/disk/by-partlabel/Arch\\x20Linux\0"
+                "\0";
+
+        _cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL;
+        _cleanup_free_ uint8_t *nulstr_copy = NULL;
+        const char *devlink;
+        const uint8_t *nulstr;
+        size_t len;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0);
+
+        /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a
+         * test for generating and parsing nulstr. For issue #17772. */
+        NULSTR_FOREACH(devlink, devlinks) {
+                log_device_info(device, "setting devlink: %s", devlink);
+                assert_se(device_add_devlink(device, devlink) >= 0);
+                assert_se(set_contains(device->devlinks, devlink));
+        }
+
+        /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
+        assert_se(device_add_property_internal(device, "SEQNUM", "1") >= 0);
+        assert_se(device_add_property_internal(device, "ACTION", "change") >= 0);
+
+        assert_se(device_get_properties_nulstr(device, &nulstr, &len) >= 0);
+        assert_se(nulstr_copy = newdup(uint8_t, nulstr, len));
+        assert_se(device_new_from_nulstr(&from_nulstr, nulstr_copy, len) >= 0);
+
+        NULSTR_FOREACH(devlink, devlinks) {
+                log_device_info(from_nulstr, "checking devlink: %s", devlink);
+                assert_se(set_contains(from_nulstr->devlinks, devlink));
+        }
+}
+
 int main(int argc, char **argv) {
         test_setup_logging(LOG_INFO);
 
@@ -168,5 +211,7 @@ int main(int argc, char **argv) {
         test_sd_device_enumerator_subsystems();
         test_sd_device_enumerator_filter_subsystem();
 
+        test_sd_device_new_from_nulstr();
+
         return 0;
 }
index 60de2dccad505e87f5b0467dd23c2ebfea1de7e1..0ee6702068b29f29ab47e075c013087d23ffad63 100644 (file)
@@ -8,12 +8,12 @@
 #include "sd-messages.h"
 
 #include "alloc-util.h"
+#include "async.h"
 #include "fd-util.h"
 #include "logind-button.h"
 #include "missing_input.h"
 #include "string-util.h"
 #include "util.h"
-#include "async.h"
 
 #define CONST_MAX5(a, b, c, d, e) CONST_MAX(CONST_MAX(a, b), CONST_MAX(CONST_MAX(c, d), e))
 
@@ -60,11 +60,7 @@ void button_free(Button *b) {
         sd_event_source_unref(b->io_event_source);
         sd_event_source_unref(b->check_event_source);
 
-        if (b->fd >= 0)
-                /* If the device has been unplugged close() returns
-                 * ENODEV, let's ignore this, hence we don't use
-                 * safe_close() */
-                (void) asynchronous_close(b->fd);
+        asynchronous_close(b->fd);
 
         free(b->name);
         free(b->seat);
@@ -72,19 +68,9 @@ void button_free(Button *b) {
 }
 
 int button_set_seat(Button *b, const char *sn) {
-        char *s;
-
         assert(b);
-        assert(sn);
 
-        s = strdup(sn);
-        if (!s)
-                return -ENOMEM;
-
-        free(b->seat);
-        b->seat = s;
-
-        return 0;
+        return free_and_strdup(&b->seat, sn);
 }
 
 static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
@@ -327,14 +313,14 @@ static int button_set_mask(const char *name, int fd) {
 }
 
 int button_open(Button *b) {
-        _cleanup_close_ int fd = -1;
+        _cleanup_(asynchronous_closep) int fd = -1;
         const char *p;
         char name[256];
         int r;
 
         assert(b);
 
-        b->fd = safe_close(b->fd);
+        b->fd = asynchronous_close(b->fd);
 
         p = strjoina("/dev/input/", b->name);
 
@@ -345,12 +331,10 @@ int button_open(Button *b) {
         r = button_suitable(fd);
         if (r < 0)
                 return log_warning_errno(r, "Failed to determine whether input device %s is relevant to us: %m", p);
-        if (r == 0) {
-                b->fd = TAKE_FD(fd);
+        if (r == 0)
                 return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
                                        "Device %s does not expose keys or switches relevant to us, ignoring.", p);
-        }
-        
+
         if (ioctl(fd, EVIOCGNAME(sizeof name), name) < 0)
                 return log_error_errno(errno, "Failed to get input name for %s: %m", p);
 
index 033fcd1f47a0008f14735109e2e142ccf657ea24..089fd69e29b754e1e556374ce703d822163d6d1e 100644 (file)
@@ -22,7 +22,7 @@
  * PID1 because 16MB of free space is required. */
 #define TMPFS_LIMITS_RUN             ",size=20%,nr_inodes=800k"
 
-/* The limit used for various nested tmpfs mounts, in paricular for guests started by systemd-nspawn.
+/* The limit used for various nested tmpfs mounts, in particular for guests started by systemd-nspawn.
  * 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25%
  * translates to 1M inodes.
  * (On the host, /tmp is configured through a .mount unit file.) */
index f7d2d984c96510688f02cb33f56c43711f18ad50..6b9ff8531bbe171a68a0cfa6b0c71fb55aa8aacb 100644 (file)
@@ -5,12 +5,45 @@
 #if HAVE_QRENCODE
 #include <qrencode.h>
 
+#include "alloc-util.h"
 #include "dlfcn-util.h"
 #include "locale-util.h"
 #include "terminal-util.h"
 
 #define ANSI_WHITE_ON_BLACK "\033[40;37;1m"
 
+static void *qrcode_dl = NULL;
+
+static QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) = NULL;
+static void (*sym_QRcode_free)(QRcode *qrcode) = NULL;
+
+int dlopen_qrencode(void) {
+        _cleanup_(dlclosep) void *dl = NULL;
+        int r;
+
+        if (qrcode_dl)
+                return 0; /* Already loaded */
+
+        dl = dlopen("libqrencode.so.4", RTLD_LAZY);
+        if (!dl)
+                return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "libqrcode support is not installed: %s", dlerror());
+
+        r = dlsym_many_and_warn(
+                        dl,
+                        LOG_DEBUG,
+                        DLSYM_ARG(QRcode_encodeString),
+                        DLSYM_ARG(QRcode_free),
+                        NULL);
+        if (r < 0)
+                return r;
+
+        /* Note that we never release the reference here, because there's no real reason to, after all this
+         * was traditionally a regular shared library dependency which lives forever too. */
+        qrcode_dl = TAKE_PTR(dl);
+        return 1;
+}
+
 static void print_border(FILE *output, unsigned width) {
         /* Four rows of border */
         for (unsigned y = 0; y < 4; y += 2) {
@@ -65,9 +98,6 @@ static void write_qrcode(FILE *output, QRcode *qr) {
 }
 
 int print_qrcode(FILE *out, const char *header, const char *string) {
-        QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
-        void (*sym_QRcode_free)(QRcode *qrcode);
-        _cleanup_(dlclosep) void *dl = NULL;
         QRcode* qr;
         int r;
 
@@ -76,17 +106,7 @@ int print_qrcode(FILE *out, const char *header, const char *string) {
         if (!is_locale_utf8() || !colors_enabled())
                 return -EOPNOTSUPP;
 
-        dl = dlopen("libqrencode.so.4", RTLD_LAZY);
-        if (!dl)
-                return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                       "QRCODE support is not installed: %s", dlerror());
-
-        r = dlsym_many_and_warn(
-                        dl,
-                        LOG_DEBUG,
-                        DLSYM_ARG(QRcode_encodeString),
-                        DLSYM_ARG(QRcode_free),
-                        NULL);
+        r = dlopen_qrencode();
         if (r < 0)
                 return r;
 
index 6fc45c93d1a1360f50be6064c120f8e2b1daa2d8..b64ecce80a3e9590379a034af2458fc98488e6de 100644 (file)
@@ -5,6 +5,8 @@
 #include <errno.h>
 
 #if HAVE_QRENCODE
+int dlopen_qrencode(void);
+
 int print_qrcode(FILE *out, const char *header, const char *string);
 #else
 static inline int print_qrcode(FILE *out, const char *header, const char *string) {
index 9e781f88dcb30b29f8f6897b7c9b73a3a8219777..3afe5d58cbd7dcd6f472432121af64190f0de71b 100644 (file)
@@ -71,6 +71,10 @@ tests += [
           libshared],
          []],
 
+        [['src/test/test-dlopen-so.c'],
+         [libshared],
+         []],
+
         [['src/test/test-job-type.c'],
          [libcore,
           libshared],
diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c
new file mode 100644 (file)
index 0000000..6436dc6
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "cryptsetup-util.h"
+#include "idn-util.h"
+#include "macro.h"
+#include "main-func.h"
+#include "pwquality-util.h"
+#include "qrcode-util.h"
+#include "tests.h"
+
+static int run(int argc, char **argv) {
+        test_setup_logging(LOG_DEBUG);
+
+        /* Try to load each of our weak library dependencies once. This is supposed to help finding cases
+         * where .so versions change and distributions update, but systemd doesn't have the new so names
+         * around yet. */
+
+#if HAVE_LIBIDN2 || HAVE_LIBIDN
+        assert_se(dlopen_idn() >= 0);
+#endif
+
+#if HAVE_LIBCRYPTSETUP
+        assert_se(dlopen_cryptsetup() >= 0);
+#endif
+
+#if HAVE_PWQUALITY
+        assert_se(dlopen_pwquality() >= 0);
+#endif
+
+#if HAVE_QRENCODE
+        assert_se(dlopen_qrencode() >= 0);
+#endif
+
+        return 0;
+}
+
+DEFINE_MAIN_FUNCTION(run);
index 16314d051b6d1f529137ab01b0e5fe9fe8830247..897940824255d70f31ca4d36a2b68c453d2436f9 100644 (file)
@@ -150,6 +150,56 @@ static void test_set_ensure_consume(void) {
         assert_se(set_size(m) == 2);
 }
 
+static void test_set_strjoin(void) {
+        _cleanup_set_free_ Set *m = NULL;
+        _cleanup_free_ char *joined = NULL;
+
+        assert_se(set_strjoin(m, NULL, &joined) >= 0);
+        assert_se(!joined);
+        assert_se(set_strjoin(m, "", &joined) >= 0);
+        assert_se(!joined);
+        assert_se(set_strjoin(m, " ", &joined) >= 0);
+        assert_se(!joined);
+        assert_se(set_strjoin(m, "xxx", &joined) >= 0);
+        assert_se(!joined);
+
+        assert_se(set_put_strdup(&m, "aaa") == 1);
+
+        assert_se(set_strjoin(m, NULL, &joined) >= 0);
+        assert_se(streq(joined, "aaa"));
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, "", &joined) >= 0);
+        assert_se(streq(joined, "aaa"));
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, " ", &joined) >= 0);
+        assert_se(streq(joined, "aaa"));
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, "xxx", &joined) >= 0);
+        assert_se(streq(joined, "aaa"));
+
+        assert_se(set_put_strdup(&m, "bbb") == 1);
+        assert_se(set_put_strdup(&m, "aaa") == 0);
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, NULL, &joined) >= 0);
+        assert_se(STR_IN_SET(joined, "aaabbb", "bbbaaa"));
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, "", &joined) >= 0);
+        assert_se(STR_IN_SET(joined, "aaabbb", "bbbaaa"));
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, " ", &joined) >= 0);
+        assert_se(STR_IN_SET(joined, "aaa bbb", "bbb aaa"));
+
+        joined = mfree(joined);
+        assert_se(set_strjoin(m, "xxx", &joined) >= 0);
+        assert_se(STR_IN_SET(joined, "aaaxxxbbb", "bbbxxxaaa"));
+}
+
 int main(int argc, const char *argv[]) {
         test_set_steal_first();
         test_set_free_with_destructor();
@@ -160,6 +210,7 @@ int main(int argc, const char *argv[]) {
         test_set_ensure_allocated();
         test_set_ensure_put();
         test_set_ensure_consume();
+        test_set_strjoin();
 
         return 0;
 }
index bde18f756e446695f882a56eee9fad186a53d533..2cc78c9e2f4294d0d1b91c1364671d55182f182c 100644 (file)
@@ -214,20 +214,23 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
         if (!filename)
                 return log_oom();
 
-        if (!add && unlink(filename) == 0)
-                (void) rmdir(dirname);
-
-        if (add)
-                do {
+        if (!add) {
+                if (unlink(filename) == 0)
+                        (void) rmdir(dirname);
+        } else
+                for (;;) {
                         _cleanup_close_ int fd = -1;
 
                         r = mkdir_parents(filename, 0755);
                         if (!IN_SET(r, 0, -ENOENT))
-                                break;
+                                return r;
+
                         fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
-                        if (fd < 0)
-                                r = -errno;
-                } while (r == -ENOENT);
+                        if (fd >= 0)
+                                break;
+                        if (errno != ENOENT)
+                                return -errno;
+                }
 
         /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
          * will be fixed in the second invocation. */
index d24b8d43985babfdf9683723cea846e8be509518..19e4951a6e4f6011b0363d40e451e48dd2e03511 100644 (file)
@@ -1089,8 +1089,7 @@ static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, co
         switch (type) {
         case UDEV_CTRL_SET_LOG_LEVEL:
                 log_debug("Received udev control message (SET_LOG_LEVEL), setting log_level=%i", value->intval);
-                log_set_max_level_realm(LOG_REALM_UDEV, value->intval);
-                log_set_max_level_realm(LOG_REALM_SYSTEMD, value->intval);
+                log_set_max_level_all_realms(value->intval);
                 manager_kill_workers(manager);
                 break;
         case UDEV_CTRL_STOP_EXEC_QUEUE:
index d5da8e0ea5e621d3078e8e3cd1ab1c5faa10c273..91cd7312d6e6f533832a21944368d535ee22d435 100644 (file)
@@ -676,6 +676,19 @@ install_missing_libraries() {
     for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/{,tests/{,manual/,unsafe/}}*; do
         LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i):$(get_ldpath $i)/src/udev" inst_libs $i
     done
+
+    # A number of dependencies is now optional via dlopen, so the install
+    # script will not pick them up, since it looks at linkage.
+    for lib in libcryptsetup libidn libidn2 pwquality libqrencode; do
+            if pkg-config --exists ${lib}; then
+                    path=$(pkg-config --variable=libdir ${lib})
+                    if ! [[ ${lib} =~ ^lib ]]; then
+                            lib="lib${lib}"
+                    fi
+                    inst_libs "${path}/${lib}.so"
+                    inst_library "${path}/${lib}.so"
+            fi
+    done
 }
 
 cleanup_loopdev() {
index ffceefb6a57ae2fe1beb5d0923aef7fc88fad0ca..19f5683f57a104fa01ae4c54531db07462a6e537 100755 (executable)
@@ -2,14 +2,26 @@
 set -ex
 set -o pipefail
 
+function has_tag_internal() {
+    udevadm info /dev/null | sed -n '/E: '$1'=/ {s/E: '$1'=/:/; s/$/:/; p}' | grep -q ":$2:"
+}
+
+function has_tag() {
+    has_tag_internal TAGS $1
+}
+
+function has_current_tag() {
+    has_tag_internal CURRENT_TAGS $1
+}
+
 mkdir -p /run/udev/rules.d/
 
 ! test -f /run/udev/tags/added/c1:3 &&
     ! test -f /run/udev/tags/changed/c1:3 &&
-    udevadm info /dev/null | grep -q -v 'E: TAGS=.*:added:.*' &&
-    udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' &&
-    udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' &&
-    udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*'
+    ! has_tag added &&
+    ! has_current_tag added &&
+    ! has_tag changed &&
+    ! has_current_tag changed
 
 cat > /run/udev/rules.d/50-testsuite.rules <<EOF
 ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", TAG+="added"
@@ -22,10 +34,10 @@ udevadm trigger -c add /dev/null
 while : ; do
     test -f /run/udev/tags/added/c1:3 &&
         ! test -f /run/udev/tags/changed/c1:3 &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' &&
+        has_tag added &&
+        has_current_tag added &&
+        ! has_tag changed &&
+        ! has_current_tag changed &&
         break
 
     sleep .5
@@ -37,10 +49,10 @@ udevadm trigger -c change /dev/null
 while : ; do
     test -f /run/udev/tags/added/c1:3 &&
         test -f /run/udev/tags/changed/c1:3 &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' &&
-        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' &&
+        has_tag added &&
+        ! has_current_tag added &&
+        has_tag changed &&
+        has_current_tag changed &&
         break
 
     sleep .5
@@ -52,10 +64,10 @@ udevadm trigger -c add /dev/null
 while : ; do
     test -f /run/udev/tags/added/c1:3 &&
         test -f /run/udev/tags/changed/c1:3 &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' &&
-        udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' &&
-        udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' &&
+        has_tag added &&
+        has_current_tag added &&
+        has_tag changed &&
+        ! has_current_tag changed &&
         break
 
     sleep .5
index 9834b06a43844458a2584e8d38a8406d66ed7763..d5b0a9b96e0e74a1d5fc194a02e0bbf33c9a4819 100644 (file)
@@ -24,6 +24,7 @@ BusName=org.freedesktop.network1
 CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
 DeviceAllow=char-* rw
 ExecStart=!!@rootlibexecdir@/systemd-networkd
+ExecReload=networkctl reload
 LockPersonality=yes
 MemoryDenyWriteExecute=yes
 NoNewPrivileges=yes