]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udevadm: improve symlink query output
authordongshengyuan <545258830@qq.com>
Fri, 31 Jul 2026 07:10:51 +0000 (15:10 +0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 2 Aug 2026 10:16:19 +0000 (19:16 +0900)
Implement the TODO item for `udevadm info -q symlink`: keep the
default space-separated output pager-free, and make `--value` print
one symlink per line with an empty separator line between devices.

TODO.md
man/udevadm.xml
src/udev/udevadm-info.c
test/units/TEST-17-UDEV.symlink-query.sh [new file with mode: 0755]

diff --git a/TODO.md b/TODO.md
index db817f33c3694424894fb44767b37c9d5ee72605..1697add812fa53611e5585be8754b1da3181bb44 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -2804,10 +2804,6 @@ SPDX-License-Identifier: LGPL-2.1-or-later
   - re-enable ProtectClock= once only cgroupsv2 is supported.
     See f562abe2963bad241d34e0b308e48cf114672c84.
 
-- **udevadm: to make symlink querying with udevadm nicer:**
-  - do not enable the pager for queries like 'udevadm info -q symlink -r'
-  - add mode with newlines instead of spaces (for grep)?
-
 - udevd: extend memory pressure logic: also kill any idle worker processes
 
 - unify how blockdev_get_root() and sysupdate find the default root block device
index e13ff9842be57f876d0ca192c5d43d1fa8218184..82f24d715a9659f20709375903e51a2bd5a9e98b 100644 (file)
           <listitem>
             <para>When showing device properties using the <option>--query=property</option>
             option, print only their values, and skip the property name and <literal>=</literal>.</para>
+            <para>When showing device symlinks using the <option>--query=symlink</option> option,
+            print one path per line instead of separating paths with spaces. An empty line is printed
+            after each device, including the last one.</para>
             <para>Cannot be used together with <option>-x/--export</option> or
             <option>-P/--export-prefix</option>.</para>
 
index 9defc516bd7239212f83d31a9b2789d23f0da4f5..439cdfd7436f66ba8cecedc983eec39cdce177c2 100644 (file)
@@ -748,9 +748,15 @@ static int query_device(QueryType query, sd_device* device) {
                 FOREACH_DEVICE_DEVLINK(device, devlink) {
                         if (!arg_root)
                                 assert_se(devlink = path_startswith(devlink, "/dev/"));
-                        printf("%s%s", prefix, devlink);
-                        prefix = " ";
+
+                        if (arg_value)
+                                printf("%s\n", devlink);
+                        else {
+                                printf("%s%s", prefix, devlink);
+                                prefix = " ";
+                        }
                 }
+
                 puts("");
                 return 0;
         }
@@ -1024,8 +1030,7 @@ static int parse_argv(int argc, char *argv[]) {
                         }
                         break;
 
-                OPTION_LONG("value", NULL,
-                            "When showing properties, print only their values"):
+                OPTION_LONG("value", NULL, "Print only values"):
                         arg_value = true;
                         break;
 
@@ -1213,7 +1218,11 @@ int verb_info_main(int argc, char *argv[], uintptr_t _data, void *userdata) {
         if (arg_action_type == ACTION_DEVICE_ID_FILE)
                 return stat_device();
 
-        pager_open(arg_pager_flags);
+        PagerFlags pager_flags = arg_pager_flags;
+        if (arg_action_type == ACTION_QUERY && arg_query == QUERY_SYMLINK && !arg_value)
+                pager_flags |= PAGER_DISABLE;
+
+        pager_open(pager_flags);
 
         if (arg_action_type == ACTION_EXPORT)
                 return export_devices();
diff --git a/test/units/TEST-17-UDEV.symlink-query.sh b/test/units/TEST-17-UDEV.symlink-query.sh
new file mode 100755 (executable)
index 0000000..f3dc03a
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+set -o pipefail
+
+# shellcheck source=test/units/util.sh
+. "$(dirname "$0")"/util.sh
+
+assert_array_contains() {
+    local needle="${1:?}"
+    local item
+
+    shift
+    for item in "$@"; do
+        [[ "$item" == "$needle" ]] && return 0
+    done
+
+    echo >&2 "FAIL: '$needle' not found"
+    return 1
+}
+
+# shellcheck disable=SC2329
+cleanup() {
+    set +e
+
+    rm -f "$rules"
+    udevadm control --reload
+    udevadm trigger --settle --action change /dev/null /dev/full
+    rm -rf /dev/test-udevadm-symlink-query
+}
+
+rules="/run/udev/rules.d/99-test-17.symlink-query.rules"
+
+trap cleanup EXIT
+
+mkdir -p "${rules%/*}"
+cat >"$rules" <<'EOF'
+SUBSYSTEM=="mem", KERNEL=="null", SYMLINK+="test-udevadm-symlink-query/null-a"
+SUBSYSTEM=="mem", KERNEL=="null", SYMLINK+="test-udevadm-symlink-query/null-b"
+SUBSYSTEM=="mem", KERNEL=="full", SYMLINK+="test-udevadm-symlink-query/full-a"
+SUBSYSTEM=="mem", KERNEL=="full", SYMLINK+="test-udevadm-symlink-query/full-b"
+EOF
+udevadm control --reload
+udevadm trigger --settle --action change /dev/null /dev/full
+
+read -r -a null_links < <(udevadm info -q symlink /dev/null)
+read -r -a full_links < <(udevadm info -q symlink /dev/full)
+
+assert_array_contains "test-udevadm-symlink-query/null-a" "${null_links[@]}"
+assert_array_contains "test-udevadm-symlink-query/null-b" "${null_links[@]}"
+assert_array_contains "test-udevadm-symlink-query/full-a" "${full_links[@]}"
+assert_array_contains "test-udevadm-symlink-query/full-b" "${full_links[@]}"
+
+mapfile -t links_by_value < <(udevadm info -q symlink --value /dev/null /dev/full)
+value_null_links=()
+value_full_links=()
+n_separators=0
+
+for link in "${links_by_value[@]}"; do
+    if [[ -z "$link" ]]; then
+        n_separators=$((n_separators + 1))
+        continue
+    fi
+
+    case "$n_separators" in
+        0)
+            value_null_links+=("$link")
+            ;;
+        1)
+            value_full_links+=("$link")
+            ;;
+        *)
+            assert_not_reached
+    esac
+done
+
+assert_eq "$n_separators" 2
+assert_eq "${#value_null_links[@]}" "${#null_links[@]}"
+assert_eq "${#value_full_links[@]}" "${#full_links[@]}"
+
+for link in "${null_links[@]}"; do
+    assert_array_contains "$link" "${value_null_links[@]}"
+done
+for link in "${full_links[@]}"; do
+    assert_array_contains "$link" "${value_full_links[@]}"
+done
+
+exit 0