summaryrefslogtreecommitdiffstats
path: root/tests/ts/lsfd
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtests/ts/lsfd/column-ainodeclass52
-rwxr-xr-xtests/ts/lsfd/column-kthread41
-rwxr-xr-xtests/ts/lsfd/column-name74
-rwxr-xr-xtests/ts/lsfd/column-type60
-rw-r--r--tests/ts/lsfd/lsfd-functions.bash85
-rwxr-xr-xtests/ts/lsfd/mkfds-directory109
-rwxr-xr-xtests/ts/lsfd/mkfds-mapped-packet-socket65
-rwxr-xr-xtests/ts/lsfd/mkfds-netlink-groups59
-rwxr-xr-xtests/ts/lsfd/mkfds-netlink-protocol58
-rwxr-xr-xtests/ts/lsfd/mkfds-netns72
-rwxr-xr-xtests/ts/lsfd/mkfds-pidfd51
-rwxr-xr-xtests/ts/lsfd/mkfds-ping142
-rwxr-xr-xtests/ts/lsfd/mkfds-pipe-no-fork124
-rwxr-xr-xtests/ts/lsfd/mkfds-raw49
-rwxr-xr-xtests/ts/lsfd/mkfds-raw650
-rwxr-xr-xtests/ts/lsfd/mkfds-ro-block-device80
-rwxr-xr-xtests/ts/lsfd/mkfds-ro-regular-file78
-rwxr-xr-xtests/ts/lsfd/mkfds-rw-character-device50
-rwxr-xr-xtests/ts/lsfd/mkfds-socketpair48
-rwxr-xr-xtests/ts/lsfd/mkfds-symlink45
-rwxr-xr-xtests/ts/lsfd/mkfds-tcp50
-rwxr-xr-xtests/ts/lsfd/mkfds-tcp651
-rwxr-xr-xtests/ts/lsfd/mkfds-udp138
-rwxr-xr-xtests/ts/lsfd/mkfds-udp6139
-rwxr-xr-xtests/ts/lsfd/mkfds-unix-dgram68
-rwxr-xr-xtests/ts/lsfd/mkfds-unix-in-netns109
-rwxr-xr-xtests/ts/lsfd/mkfds-unix-stream98
-rwxr-xr-xtests/ts/lsfd/option-filter-broken-exp36
-rwxr-xr-xtests/ts/lsfd/option-inet98
-rwxr-xr-xtests/ts/lsfd/option-pid80
-rwxr-xr-xtests/ts/lsfd/option-summary62
31 files changed, 2321 insertions, 0 deletions
diff --git a/tests/ts/lsfd/column-ainodeclass b/tests/ts/lsfd/column-ainodeclass
new file mode 100755
index 0000000..6391c48
--- /dev/null
+++ b/tests/ts/lsfd/column-ainodeclass
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="ainodeclass column"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF/lsfd-functions.bash"
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR="(FD == 3)"
+
+for C in pidfd inotify; do
+ ts_init_subtest $C
+ {
+ coproc MKFDS { "$TS_HELPER_MKFDS" $C $FD ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n -o ASSOC,STTYPE,AINODECLASS -p "${PID}" -Q "${EXPR}"
+ echo "$C"':ASSOC,STTYPE,AINODECLASS': $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+ } > "$TS_OUTPUT" 2>&1
+ if [ "$C-$?" == "pidfd-$ENOSYS" ]; then
+ ts_skip_subtest "pidfd_open(2) is not available"
+ continue
+ fi
+ ts_finalize_subtest
+done
+
+ts_finalize
diff --git a/tests/ts/lsfd/column-kthread b/tests/ts/lsfd/column-kthread
new file mode 100755
index 0000000..0b093e9
--- /dev/null
+++ b/tests/ts/lsfd/column-kthread
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="kthread column"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_prog "ps"
+
+[ "$(ps --no-headers -o comm 1)" = 'systemd' ] || ts_skip "pid 1 is not systemd"
+[ "$(ps --no-headers -o comm 2)" = 'kthreadd' ] || ts_skip "pid 2 is not kthreadd"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ "$TS_CMD_LSFD" -o COMMAND,PID,USER,MODE,TYPE,NAME,KTHREAD \
+ -Q '(PID < 3) and ((ASSOC == "cwd") or (ASSOC == "rtd"))'
+ echo $?
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
+
+
diff --git a/tests/ts/lsfd/column-name b/tests/ts/lsfd/column-name
new file mode 100755
index 0000000..5dc491a
--- /dev/null
+++ b/tests/ts/lsfd/column-name
@@ -0,0 +1,74 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="NAME and KNAME column"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF/lsfd-functions.bash"
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_prog "sed"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR="(FD == 3)"
+
+make_state_connected()
+{
+ if [ "$1" = "socketpair" ]; then
+ lsfd_make_state_connected
+ else
+ cat
+ fi
+}
+
+for C in ro-regular-file pidfd socketpair; do
+ ts_init_subtest $C
+ {
+ coproc MKFDS {
+ argv=()
+ case $C in
+ socketpair)
+ argv[0]="$((FD + 1))"
+ argv[1]="socktype=DGRAM"
+ esac
+ "$TS_HELPER_MKFDS" $C $FD "${argv[@]}"
+ }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n -o ASSOC,KNAME,NAME -p "${PID}" -Q "${EXPR}" | {
+ # Replace the unpredictable an inode number for the socket
+ # with "INODENUM".
+ sed -e 's/\[[0-9]\+\]/[INODENUM]/g' | make_state_connected $C
+ }
+ echo "$C"':ASSOC,KNAME,NAME': ${PIPESTATUS[0]}
+
+ kill -CONT "${PID}"
+ fi
+ } > "$TS_OUTPUT" 2>&1
+ wait "${MKFDS_PID}"
+ if [ "$C-$?" == "pidfd-$ENOSYS" ]; then
+ ts_skip_subtest "pidfd_open(2) is not available"
+ continue
+ fi
+ ts_finalize_subtest
+done
+
+ts_finalize
diff --git a/tests/ts/lsfd/column-type b/tests/ts/lsfd/column-type
new file mode 100755
index 0000000..cf6175e
--- /dev/null
+++ b/tests/ts/lsfd/column-type
@@ -0,0 +1,60 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="TYPE and STTYPE column"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF/lsfd-functions.bash"
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR="(FD == 3)"
+
+for C in ro-regular-file pidfd inotify socketpair; do
+ ts_init_subtest $C
+ {
+ coproc MKFDS {
+ argv=()
+ case $C in
+ socketpair)
+ argv[0]="$((FD + 1))"
+ argv[1]="socktype=DGRAM"
+ esac
+ "$TS_HELPER_MKFDS" $C $FD "${argv[@]}"
+ }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n -o ASSOC,STTYPE,TYPE -p "${PID}" -Q "${EXPR}"
+ echo "$C"':ASSOC,STTYPE,TYPE': $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+ } > "$TS_OUTPUT" 2>&1
+ if [ "$C-$?" == "pidfd-$ENOSYS" ]; then
+ ts_skip_subtest "pidfd_open(2) is not available"
+ continue
+ fi
+ ts_finalize_subtest
+done
+
+ts_finalize
diff --git a/tests/ts/lsfd/lsfd-functions.bash b/tests/ts/lsfd/lsfd-functions.bash
new file mode 100644
index 0000000..d9a3595
--- /dev/null
+++ b/tests/ts/lsfd/lsfd-functions.bash
@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+# The exit-status used in a test target.
+readonly ENOSYS=17
+readonly EPERM=18
+readonly ENOPROTOOPT=19
+readonly EPROTONOSUPPORT=20
+readonly EACCESS=21
+
+function lsfd_wait_for_pausing {
+ ts_check_prog "sleep"
+
+ local PID=$1
+ until [[ $(ps --no-headers -ostat "${PID}") =~ S.* ]]; do
+ sleep 1
+ done
+}
+
+function lsfd_compare_dev {
+ local LSFD=$1
+ local FILE=$2
+ local EXPR=$3
+
+ ts_check_prog "grep"
+ ts_check_prog "expr"
+ ts_check_prog "stat"
+
+ local DEV=$("${LSFD}" --raw -n -o DEV -Q "${EXPR}")
+ echo 'DEV[RUN]:' $?
+ local MAJ=${DEV%:*}
+ local MIN=${DEV#*:}
+ local DEVNUM=$(( ( MAJ << 8 ) + MIN ))
+ local STAT_DEVNUM=$(stat -c "%d" "$FILE")
+ echo 'STAT[RUN]:' $?
+ if [ "${DEVNUM}" == "${STAT_DEVNUM}" ]; then
+ echo 'DEVNUM[STR]:' 0
+ else
+ echo 'DEVNUM[STR]:' 1
+ # Print more information for debugging
+ echo 'DEV:' "${DEV}"
+ echo 'MAJ:MIN' "${MAJ}:${MIN}"
+ echo 'DEVNUM:' "${DEVNUM}"
+ echo 'STAT_DEVNUM:' "${STAT_DEVNUM}"
+ fi
+}
+
+lsfd_strip_type_stream()
+{
+ # lsfd changes the output of NAME column for a unix stream socket
+ # whether the kernel reports it is a "UNIX-STREAM" socket or a
+ # "UNIX" socket. For "UNIX", lsfd appends "type=stream" to the
+ # NAME column. Let's delete the appended string before comparing.
+ sed -e 's/ type=stream//'
+}
+
+lsfd_make_state_connected()
+{
+ # Newer kernels report the states of unix dgram sockets created by
+ # sockerpair(2) are "connected" via /proc/net/unix though Older
+ # kernels report "unconnected".
+ #
+ # Newer kernels report the states of unix dgram sockets already
+ # connect(2)'ed are "connected", too.
+ #
+ # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=83301b5367a98c17ec0d76c7bc0ccdc3c7e7ad6d
+ #
+ # This rewriting adjusts the output of lsfd running on older kernels
+ # to that on newer kernels.
+ sed -e 's/state=unconnected/state=connected/'
+}
diff --git a/tests/ts/lsfd/mkfds-directory b/tests/ts/lsfd/mkfds-directory
new file mode 100755
index 0000000..ef769c9
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-directory
@@ -0,0 +1,109 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="directory"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_CMD_FINDMNT"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_check_prog "stat"
+ts_check_prog "id"
+ts_check_prog "sed"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR=
+DIR=/
+
+mntflag=$(findmnt -n -o OPTIONS -T $DIR)
+noatime=
+case "${mntflag}" in
+ *noatime*)
+ noatime=1
+esac
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" directory $FD dir=$DIR; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and (FD == '"$FD"')'
+ ${TS_CMD_LSFD} -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "${EXPR}" | {
+ #
+ # Normalize the output:
+ #
+ # See https://github.com/util-linux/util-linux/issues/1511#issuecomment-1029968595
+ # It seems that syscalls opening a directory on mips64 GNU/Linux take the
+ # O_LARGEFILE flag.
+ #
+ sed -e 's/largefile,\|,largefile//'
+ } | {
+ #
+ # Normalize the output:
+ #
+ # See https://github.com/util-linux/util-linux/issues/1709#issuecomment-1156333293
+ # If the file system where the target directory ($DIR) is mounted with
+ # "noatime" flag, Linux kernel may set O_NOATIME to the fd associated with $DIR.
+ #
+ if [ "$noatime" = 1 ]; then
+ sed -e 's/noatime,\|,noatime//'
+ else
+ cat
+ fi
+ }
+ echo 'ASSOC,MODE,TYPE,FLAGS,NAME': $?
+
+ LSFD_PID=$(${TS_CMD_LSFD} --raw -n -o PID -Q "${EXPR}")
+ echo 'PID[RUN]:' $?
+ [ "${LSFD_PID}" == "${PID}" ]
+ echo 'PID[STR]:' $?
+
+ LSFD_INODE=$(${TS_CMD_LSFD} --raw -n -o INODE -Q "${EXPR}")
+ echo 'INODE[RUN]:' $?
+ [ "${LSFD_INODE}" == "$(stat -c %i /)" ]
+ echo 'INODE[STR]:' $?
+
+ LSFD_UID=$(${TS_CMD_LSFD} --raw -n -o UID -Q "${EXPR}")
+ echo 'UID[RUN]:' $?
+ [ "${LSFD_UID}" == $(id -u) ]
+ echo 'UID[STR]:' $?
+
+ LSFD_USER=$(${TS_CMD_LSFD} --raw -n -o USER -Q "${EXPR}")
+ echo 'USER[RUN]:' $?
+ [ "${LSFD_USER}" == $(id -u -n) ]
+ echo 'USER[STR]:' $?
+
+ LSFD_NLINK=$(${TS_CMD_LSFD} --raw -n -o NLINK -Q "${EXPR}")
+ echo 'NLINK[RUN]:' $?
+ if [ "${LSFD_NLINK}" == $(stat -c %h /) ]; then
+ echo 'NLINK[STR]:' 0
+ else
+ echo 'NLINK[STR]:' 1
+ echo 'LSFD_NLINK:' "${LSFD_NLINK}"
+ echo 'stat reports:' "$(stat -c %h /)"
+ fi
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-mapped-packet-socket b/tests/ts/lsfd/mkfds-mapped-packet-socket
new file mode 100755
index 0000000..a1fb68f
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-mapped-packet-socket
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="mmap'ed AF_PACKET socket"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+ts_skip_docker
+
+. "$TS_SELF"/lsfd-functions.bash
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR=
+INTERFACE=lo
+SOCKTYPE=
+ERR=
+
+for SOCKTYPE in RAW DGRAM; do
+ coproc MKFDS { "$TS_HELPER_MKFDS" mapped-packet-socket $FD \
+ interface=${INTERFACE} socktype=${SOCKTYPE}; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(ASSOC == "shm") and (STTYPE == "SOCK") and (MODE == "-w-")'
+ ${TS_CMD_LSFD} -p "$PID" -n -o SOCK.PROTONAME -Q "${EXPR}"
+ echo 'SOCK.PROTONAME': $?
+
+ EXPR="(FD == $FD)"
+ ${TS_CMD_LSFD} -p "$PID" -n -o NAME,SOCK.TYPE,SOCK.PROTONAME,PACKET.IFACE,PACKET.PROTOCOL -Q "${EXPR}"
+ echo 'NAME,SOCK.TYPE,SOCK.PROTONAME,PACKET.IFACE,PACKET.PROTOCOL': $?
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+ ERR=$?
+ if [ $ERR != 0 ]; then
+ break
+ fi
+done > $TS_OUTPUT 2>&1
+
+if [[ "$ERR" == "$ENOPROTOOPT" ]]; then
+ ts_skip "packet socket doesn't support attaching a buffer on this platform"
+fi
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-netlink-groups b/tests/ts/lsfd/mkfds-netlink-groups
new file mode 100755
index 0000000..896b50c
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-netlink-groups
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="NETLINK sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+
+. "$TS_SELF"/lsfd-functions.bash
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR='(TYPE == "NETLINK") and (FD == 3)'
+NETLINK_PROTOCOL=4
+NETLINK_LPORT=
+NETLINK_GROUPS=5
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" netlink $FD protocol=$NETLINK_PROTOCOL groups=$NETLINK_GROUPS; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,NETLINK.PROTOCOL,NETLINK.GROUPS \
+ -p "${PID}" -Q "${EXPR}" | sed -e "s/lport=${PID}/lport=/g"
+ echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,NETLINK.PROTOCOL,NETLINK.GROUPS': ${PIPESTATUS[0]}
+ NETLINK_LPORT=$(${TS_CMD_LSFD} --raw -n -o NETLINK.LPORT -p "${PID}" -Q "${EXPR}")
+ if [ "${NETLINK_LPORT}" == "${PID}" ]; then
+ echo 'LPORT: OK'
+ else
+ printf "LPORT: FAILED (PID: %d != NETLINK.LPORT: %d)\n" "${PID}" "${NETLINK_LPORT}"
+ fi
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+if [[ $? == "$EPROTONOSUPPORT" ]]; then
+ ts_skip "It seems that this platform doesn't support making a netlink socket"
+fi
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-netlink-protocol b/tests/ts/lsfd/mkfds-netlink-protocol
new file mode 100755
index 0000000..c1a5ffc
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-netlink-protocol
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="NETLINK sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF"/lsfd-functions.bash
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR='(TYPE == "NETLINK") and (FD == 3)'
+NETLINK_PROTOCOL=4
+NETLINK_LPORT=
+NETLINK_GROUPS=5
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" netlink $FD protocol=$NETLINK_PROTOCOL; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,NETLINK.PROTOCOL,NETLINK.GROUPS \
+ -p "${PID}" -Q "${EXPR}" | sed -e "s/lport=${PID}/lport=/g"
+ echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,NETLINK.PROTOCOL': ${PIPESTATUS[0]}
+ NETLINK_LPORT=$(${TS_CMD_LSFD} --raw -n -o NETLINK.LPORT -p "${PID}" -Q "${EXPR}")
+ if [ "${NETLINK_LPORT}" == "${PID}" ]; then
+ echo 'LPORT: OK'
+ else
+ printf "LPORT: FAILED (PID: %d != NETLINK.LPORT: %d)\n" "${PID}" "${NETLINK_LPORT}"
+ fi
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+if [[ $? == "$EPROTONOSUPPORT" ]]; then
+ ts_skip "It seems that this platform doesn't support making a netlink socket"
+fi
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-netns b/tests/ts/lsfd/mkfds-netns
new file mode 100755
index 0000000..cd110f6
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-netns
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="netns associated with a fd"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+ts_skip_docker
+
+. "$TS_SELF/lsfd-functions.bash"
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+NAME_FD=
+NAME_NS=
+INO_FD=
+INO_NS=
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" netns "$FD"; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ "${TS_CMD_LSFD}" -n -oNS.TYPE -p "${PID}" -Q "(FD == $FD)"
+ NAME_FD=$("${TS_CMD_LSFD}" -n -oNS.NAME -p "${PID}" -Q "(FD == $FD)")
+ NAME_NS=$("${TS_CMD_LSFD}" -n -oNS.NAME -p "${PID}" -Q '(ASSOC == "net")')
+ INO_FD=$( "${TS_CMD_LSFD}" -n -oINODE -p "${PID}" -Q "(FD == $FD)")
+ INO_NS=$( "${TS_CMD_LSFD}" -n -oINODE -p "${PID}" -Q '(ASSOC == "net")')
+
+ if [[ "$NAME_FD" = "$NAME_NS" ]]; then
+ echo "NAME_FD" == "NAME_NS": $?
+ else
+ echo "NAME_FD: $NAME_FD" == "NAME_NS: $NAME_NS": $?
+ fi
+
+ if [[ "$NAME_FD" = "net:[$INO_FD]" ]]; then
+ echo "NAME_FD" == "net:[INO_FD]": $?
+ else
+ echo "NAME_FD: $NAME_FD" == "net:[INO_FD: $INO_FD]": $?
+ fi
+
+ if [[ "$NAME_FD" = "net:[$INO_NS]" ]]; then
+ echo "NAME_FD" == "net:[INO_NS]": $?
+ else
+ echo "NAME_FD: $NAME_FD" == "net:[INO_NS: $INO_NS]": $?
+ fi
+
+ kill -CONT ${PID}
+ fi
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+if [ "$?" == "$ENOSYS" ]; then
+ ts_skip "ioctl(fd, SIOCGSKNS) is not available"
+fi
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-pidfd b/tests/ts/lsfd/mkfds-pidfd
new file mode 100755
index 0000000..aad693f
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-pidfd
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="pidfd"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF/lsfd-functions.bash"
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_prog "ps"
+
+ts_cd "$TS_OUTDIR"
+
+[ "$(ps --no-headers -o comm 1)" = 'systemd' ] || ts_skip "pid 1 is not systemd"
+
+PID=
+FD=3
+TARGET=1
+EXPR="(PID != ${TARGET}) and (FD == 3) and (PIDFD.PID == ${TARGET})"
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" pidfd $FD target-pid=${TARGET} ; }
+ if read -u ${MKFDS[0]} PID; then
+ ${TS_CMD_LSFD} -n -o ASSOC,STTYPE,SOURCE,NAME,PIDFD.COMM,PIDFD.PID -p "${PID}" -p ${TARGET} -Q "${EXPR}"
+ echo 'ASSOC,STTYPE,SOURCE,NAME,PIDFD.COMM,PIDFD.PID': $?
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+if [ "$?" == "$ENOSYS" ]; then
+ ts_skip "pidfd_open(2) is not available"
+fi
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-ping b/tests/ts/lsfd/mkfds-ping
new file mode 100755
index 0000000..c2ca049
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-ping
@@ -0,0 +1,142 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="PING and PINGv6 sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_skip_nonroot
+
+. "$TS_SELF"/lsfd-functions.bash
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_prog "id"
+
+ts_check_native_byteorder
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR=(
+ '(TYPE == "PING") and (FD == 3)'
+ '(TYPE == "PINGv6") and (FD == 3)'
+)
+FACTORY=(
+ ping
+ ping6
+)
+TYPE=(
+ 'PING'
+ 'PINGv6'
+)
+COLNS=(
+ INET
+ INET6
+)
+ID=9999
+
+range_check()
+{
+ local v=$1
+ local min=$2
+ local max=$3
+
+ [[ $min -le $v && $v -le $max ]]
+ return $?
+}
+
+ping_group_range_check()
+{
+ local g
+ local group_min group_max
+
+ if ! read group_min group_max < /proc/sys/net/ipv4/ping_group_range; then
+ # We can say nothing. Just allow to go ahead.
+ return 0
+ fi
+
+ if [[ -z "$group_min" || -z "$group_max" ]]; then
+ # We can say nothing. Just allow to go ahead.
+ return 0
+ fi
+
+ for g in $(id -G); do
+ if range_check "$g" "$group_min" "$group_max"; then
+ return 0
+ fi
+ done
+
+ return 1
+}
+
+ERRMSG=
+for i in 0 1; do
+ ERRMSG=$("$TS_HELPER_MKFDS" -c -q "${FACTORY[$i]}" 3 id=$ID 2>&1)
+ ERR="$?"
+ if [[ "$ERR" == "$EACCESS" ]]; then
+ case "$ERRMSG" in
+ *bind*)
+ MSG="making ${TYPE[$i]} socket with specifying id is not allowed (blocked by SELinux?)"
+ ;;
+ *socket*)
+ if ! ping_group_range_check; then
+ MSG="the group(s) ($(id -G)) of the process is not in the expected range"
+ MSG+=" [$(cat /proc/sys/net/ipv4/ping_group_range)])"
+ else
+ MSG="$ERRMSG"
+ fi
+ ;;
+ *)
+ MSG="$ERRMSG"
+ ;;
+ esac
+ ts_skip "${MSG}"
+ elif [[ "$ERR" != 0 ]]; then
+ ts_skip "making ${TYPE[$i]} socket is failed ($ERR: $ERRMSG)"
+ fi
+done
+
+for i in 0 1; do
+ ts_init_subtest "${FACTORY[$i]}"
+ {
+ coproc MKFDS { "$TS_HELPER_MKFDS" "${FACTORY[$i]}" $FD id=$ID; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,${COLNS[$i]}.LADDR,${COLNS[$i]}.RADDR,PING.ID \
+ -p "${PID}" -Q "${EXPR[$i]}"
+ echo "ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,${COLNS[$i]}.LADDR,${COLNS[$i]}.RADDR,PING.ID": $?
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" "${FACTORY[$i]}" $FD id=$ID connect=0; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,${COLNS[$i]}.LADDR,${COLNS[$i]}.RADDR,PING.ID \
+ -p "${PID}" -Q "${EXPR[$i]}"
+ echo "ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,${COLNS[$i]}.LADDR,${COLNS[$i]}.RADDR,PING.ID": $?
+ kill -CONT "${PID}"
+ fi
+ } > "$TS_OUTPUT" 2>&1
+ wait "${MKFDS_PID}"
+ ts_finalize_subtest
+done
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-pipe-no-fork b/tests/ts/lsfd/mkfds-pipe-no-fork
new file mode 100755
index 0000000..e28aa9d
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-pipe-no-fork
@@ -0,0 +1,124 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="pipe, no fork"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_check_prog "stat"
+ts_check_prog "readlink"
+
+ts_cd "$TS_OUTDIR"
+
+pipe_name()
+{
+ readlink /proc/$1/fd/$2
+}
+
+pipe_inode()
+{
+ stat -L -c %i /proc/$1/fd/$2
+}
+
+PID=
+FD0=3
+FD1=4
+EXPR=
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" pipe-no-fork $FD0 $FD1 nonblock=-w rdup=$((FD0 + 2)) wdup=$((FD1 + 2)); }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and ((FD == '"$FD0"') or (FD =='"$FD1"'))'
+ ${TS_CMD_LSFD} -n -o ASSOC,MODE,TYPE,SOURCE,FLAGS -Q "${EXPR}"
+ echo 'ASSOC,MODE,TYPE,SOURCE,FLAGS': $?
+
+ LSFD_PIDS=$(${TS_CMD_LSFD} --raw -n -o PID -Q "${EXPR}")
+ echo 'PID[RUN]:' $?
+ [ "${LSFD_PIDS}" == "$(printf '%d\n%d' ${PID} ${PID})" ]
+ echo 'PID[STR]:' $?
+
+ LSFD_NAMES=$(${TS_CMD_LSFD} --raw -n -o NAME -Q "${EXPR}")
+ echo 'NAMES[RUN]:' $?
+ [ "${LSFD_NAMES}" == "$(printf '%s\n%s' $(pipe_name $PID $FD0) $(pipe_name $PID $FD1))" ]
+ echo 'NAMES[STR]:' $?
+
+ LSFD_INODES=$(${TS_CMD_LSFD} --raw -n -o INODE -Q "${EXPR}")
+ echo 'INODES[RUN]:' $?
+ [ "${LSFD_INODES}" == "$(printf '%d\n%d' $(pipe_inode $PID $FD0) $(pipe_inode $PID $FD1))" ]
+ echo 'INODES[STR]:' $?
+
+ LSFD_ENDPOINTS=$(${TS_CMD_LSFD} --raw -n -o ASSOC,ENDPOINTS -Q "${EXPR}")
+ echo 'ENDPOINTS[RUN]:' $?
+ mkfds=${TS_HELPER_MKFDS##*/}
+
+ line0=$(printf '%d ' $FD0)
+ line0+=$(printf '%d,%s,%d%c%c' $PID $mkfds $FD1 - w)
+ line0+='\x0a'
+ line0+=$(printf '%d,%s,%d%c%c' $PID $mkfds $((FD0 + 2)) r -)
+ line0+='\x0a'
+ line0+=$(printf '%d,%s,%d%c%c' $PID $mkfds $((FD1 + 2)) - w)
+
+ line1=$(printf '%d ' $FD1)
+ line1+=$(printf '%d,%s,%d%c%c' $PID $mkfds $FD0 r -)
+ line1+='\x0a'
+ line1+=$(printf '%d,%s,%d%c%c' $PID $mkfds $((FD0 + 2)) r -)
+ line1+='\x0a'
+ line1+=$(printf '%d,%s,%d%c%c' $PID $mkfds $((FD1 + 2)) - w)
+
+ expected=$(printf '%s\n%s' "${line0}" "${line1}")
+ if [ "${LSFD_ENDPOINTS}" == "${expected}" ]; then
+ echo 'ENDPOINTS[STR]:' $?
+ else
+ echo "lsfd output:"
+ echo "${LSFD_ENDPOINTS}"
+ echo "expectation:"
+ echo "${expected}"
+ fi
+
+ EXPR='(PID == '"${PID}"') and (FD == '"$FD0"')'
+ LSFD_ENDPOINTS_JSON=$(${TS_CMD_LSFD} -J --raw -n -o ASSOC,ENDPOINTS -Q "${EXPR}")
+ echo 'ASSOC,ENDPOINTS (JSON)': $?
+ EXPECTED_LSFD_ENDPOINTS_JSON=$(cat<<EOF
+{
+ "lsfd": [
+ {
+ "assoc": "$FD0",
+ "endpoints": [
+ "$PID,test_mkfds,${FD1}-w", "$PID,test_mkfds,$((FD0 + 2))r-", "$PID,test_mkfds,$((FD1 + 2))-w"
+ ]
+ }
+ ]
+}
+EOF
+ )
+ if [[ "$EXPECTED_LSFD_ENDPOINTS_JSON" == "${LSFD_ENDPOINTS_JSON}" ]]; then
+ echo EXPECTED_LSFD_ENDPOINTS_JSON == LSFD_ENDPOINTS_JSON
+ else
+ echo LSFD_ENDPOINTS_JSON: "${LSFD_ENDPOINTS_JSON}"
+ echo EXPECTED_LSFD_ENDPOINTS_JSON: "${EXPECTED_LSFD_ENDPOINTS_JSON}"
+ fi
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-raw b/tests/ts/lsfd/mkfds-raw
new file mode 100755
index 0000000..0260ba1
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-raw
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="RAW sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_skip_nonroot
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR='(TYPE == "RAW") and (FD == 3)'
+PROTOCOL=5
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" raw $FD protocol=$PROTOCOL; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL \
+ -p "${PID}" -Q "${EXPR}"
+ echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET.LADDR,INET.RADDR,RAW.PROTOCOL': $?
+ kill -CONT "${PID}"
+ fi
+
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-raw6 b/tests/ts/lsfd/mkfds-raw6
new file mode 100755
index 0000000..0b82fff
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-raw6
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="RAW6 sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_skip_nonroot
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+ts_skip_docker
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR='(TYPE == "RAWv6") and (FD == 3)'
+PROTOCOL=5
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" raw6 $FD protocol=$PROTOCOL; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL \
+ -p "${PID}" -Q "${EXPR}"
+ echo 'ASSOC,TYPE,NAME,SOCK.STATE,SOCK.TYPE,INET6.LADDR,INET6.RADDR,RAW.PROTOCOL': $?
+ kill -CONT "${PID}"
+ fi
+
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-ro-block-device b/tests/ts/lsfd/mkfds-ro-block-device
new file mode 100755
index 0000000..ad5a492
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-ro-block-device
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="block device with O_RDONLY"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+ts_skip_docker
+
+# losetup cannot find an unused loop device.
+ts_skip_qemu_user
+
+. "$TS_SELF"/lsfd-functions.bash
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_CMD_LOSETUP"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+ts_device_init
+LSFD_LOOP_BDEV=$TS_LODEV
+LSFD_LOOP_BDEV_BASENAME=${LSFD_LOOP_BDEV##*/}
+LSFD_LOOP_BDEV_NUM=${LSFD_LOOP_BDEV_BASENAME#loop}
+
+PID=
+FD=3
+EXPR=
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" ro-block-device $FD blkdev=${LSFD_LOOP_BDEV}; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and (FD == '"$FD"')'
+ ${TS_CMD_LSFD} -n -o ASSOC,MODE,TYPE,POS,BLKDRV,DEVTYPE -Q "${EXPR}"
+ echo 'ASSOC,MODE,TYPE,,POS,,BLKDRV,DEVTYPE': $?
+
+ LSFD_NAME=$(${TS_CMD_LSFD} --raw -n -o NAME -Q "${EXPR}")
+ echo 'NAME[RUN]:' $?
+ [ "${LSFD_NAME}" == "${LSFD_LOOP_BDEV}" ]
+ echo 'NAME[STR]:' $?
+
+ LSFD_SOURCE=$(${TS_CMD_LSFD} --raw -n -o SOURCE -Q "${EXPR}")
+ echo 'SOURCE[RUN]:' $?
+ [ "${LSFD_SOURCE}" == "${LSFD_LOOP_BDEV_BASENAME}" ]
+ echo 'SOURCE[STR]:' $?
+
+ LSFD_MAJ_MIN=$(${TS_CMD_LSFD} --raw -n -o MAJ:MIN -Q "${EXPR}")
+ echo 'MAJ_MIN[RUN]:' $?
+ [ "${LSFD_MAJ_MIN}" == 7:"${LSFD_LOOP_BDEV_NUM}" ]
+ echo 'MAJ_MIN[STR]:' $?
+
+ LSFD_RDEV=$(${TS_CMD_LSFD} --raw -n -o RDEV -Q "${EXPR}")
+ echo 'RDEV[RUN]:' $?
+ [ "${LSFD_RDEV}" == 7:"${LSFD_LOOP_BDEV_NUM}" ]
+ echo 'RDEV[STR]:' $?
+
+ lsfd_compare_dev "${TS_CMD_LSFD}" "${LSFD_LOOP_BDEV}" "${EXPR}"
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-ro-regular-file b/tests/ts/lsfd/mkfds-ro-regular-file
new file mode 100755
index 0000000..a2c4c26
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-ro-regular-file
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="read-only regular file"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF"/lsfd-functions.bash
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_check_prog "stat"
+ts_check_prog "id"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR=
+
+{
+ target=/etc/passwd
+ coproc MKFDS { "$TS_HELPER_MKFDS" --comm ABC ro-regular-file $FD offset=1 file=$target; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and (FD == '"$FD"')'
+ ${TS_CMD_LSFD} -n -o COMMAND,ASSOC,MODE,TYPE,NAME,POS -Q "${EXPR}"
+ echo 'COMMAND,ASSOC,MODE,TYPE,NAME,POS': $?
+
+ LSFD_PID=$(${TS_CMD_LSFD} --raw -n -o PID -Q "${EXPR}")
+ echo 'PID[RUN]:' $?
+ [ "${LSFD_PID}" == "${PID}" ]
+ echo 'PID[STR]:' $?
+
+ LSFD_INODE=$(${TS_CMD_LSFD} --raw -n -o INODE -Q "${EXPR}")
+ echo 'INODE[RUN]:' $?
+ [ "${LSFD_INODE}" == "$(stat -c %i $target)" ]
+ echo 'INODE[STR]:' $?
+
+ LSFD_UID=$(${TS_CMD_LSFD} --raw -n -o UID -Q "${EXPR}")
+ echo 'UID[RUN]:' $?
+ [ "${LSFD_UID}" == $(id -u) ]
+ echo 'UID[STR]:' $?
+
+ LSFD_USER=$(${TS_CMD_LSFD} --raw -n -o USER -Q "${EXPR}")
+ echo 'USER[RUN]:' $?
+ [ "${LSFD_USER}" == $(id -u -n) ]
+ echo 'USER[STR]:' $?
+
+ LSFD_SIZE=$(${TS_CMD_LSFD} --raw -n -o SIZE -Q "${EXPR}")
+ echo 'SIZE[RUN]:' $?
+ [ "${LSFD_SIZE}" == $(stat -c %s $target) ]
+ echo 'SIZE[STR]:' $?
+
+ lsfd_compare_dev "${TS_CMD_LSFD}" $target "${EXPR}"
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-rw-character-device b/tests/ts/lsfd/mkfds-rw-character-device
new file mode 100755
index 0000000..85dd29c
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-rw-character-device
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="character device with O_RDWR"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF"/lsfd-functions.bash
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR=
+
+{
+ target=/dev/zero
+ coproc MKFDS { "$TS_HELPER_MKFDS" rw-character-device $FD chrdev=$target; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and (FD == '"$FD"')'
+ ${TS_CMD_LSFD} -n -o ASSOC,MODE,TYPE,NAME,SOURCE,POS,MAJ:MIN,CHRDRV,DEVTYPE,RDEV -Q "${EXPR}"
+ echo 'ASSOC,MODE,TYPE,NAME,SOURCE,POS,MAJ:MIN,CHRDRV,DEVTYPE,RDEV': $?
+
+ lsfd_compare_dev "${TS_CMD_LSFD}" $target "${EXPR}"
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-socketpair b/tests/ts/lsfd/mkfds-socketpair
new file mode 100755
index 0000000..3ffd088
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-socketpair
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="AF_UNIX socket pair created with socketpair(2)"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_check_prog "sed"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD0=3
+FD1=4
+EXPR=
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" socketpair $FD0 $FD1 socktype=DGRAM; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and ((FD == '"$FD0"') or (FD == '"$FD1"'))'
+ ${TS_CMD_LSFD} -n -o ASSOC,MODE,STTYPE,SOURCE,SOCK.PROTONAME -Q "${EXPR}" | sed -e 's/UNIX-DGRAM/UNIX/'
+ echo 'ASSOC,MODE,STTYPE,SOURCE,SOCK.PROTONAME': ${PIPESTATUS[0]}
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-symlink b/tests/ts/lsfd/mkfds-symlink
new file mode 100755
index 0000000..4825645
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-symlink
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="symbolic link itself opened with O_PATH"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FD=3
+EXPR=
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" symlink $FD path=/dev/stdin; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='(PID == '"${PID}"') and (FD == '"$FD"')'
+ ${TS_CMD_LSFD} -n -o ASSOC,MODE,TYPE,NAME,FLAGS -Q "${EXPR}"
+ echo 'ASSOC,MODE,TYPE,NAME,FLAGS': $?
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-tcp b/tests/ts/lsfd/mkfds-tcp
new file mode 100755
index 0000000..e531a7b
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-tcp
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="TCP sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDS=3
+FDC=4
+FDA=5
+EXPR='(TYPE == "TCP") and (FD >= 3) and (FD <= 5)'
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" tcp $FDS $FDC $FDA \
+ server-port=34567 \
+ client-port=23456 ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,TCP.LADDR,TCP.LPORT,TCP.RADDR,TCP.RPORT \
+ -p "${PID}" -Q "${EXPR}"
+ echo 'ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,TCP.LADDR,TCP.LPORT,TCP.RADDR,TCP.RPORT': $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-tcp6 b/tests/ts/lsfd/mkfds-tcp6
new file mode 100755
index 0000000..7368bfa
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-tcp6
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="TCP6 sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+ts_skip_docker
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDS=3
+FDC=4
+FDA=5
+EXPR='(TYPE == "TCPv6") and (FD >= 3) and (FD <= 5)'
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" tcp6 $FDS $FDC $FDA \
+ server-port=34567 \
+ client-port=23456 ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,TCP.LADDR,TCP.LPORT,TCP.RADDR,TCP.RPORT \
+ -p "${PID}" -Q "${EXPR}"
+ echo 'ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,TCP.LADDR,TCP.LPORT,TCP.RADDR,TCP.RPORT': $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-udp b/tests/ts/lsfd/mkfds-udp
new file mode 100755
index 0000000..e6e1f1c
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-udp
@@ -0,0 +1,138 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="UDP and UDP-Lite sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDS=3
+FDC=4
+EXPR=(
+ '(TYPE == "UDP") and (FD >= 3) and (FD <= 4)'
+ '(TYPE == "UDP-Lite") and (FD >= 3) and (FD <= 4)'
+)
+EXPR_server=(
+ '(TYPE == "UDP") and (FD == 3)'
+ '(TYPE == "UDP-Lite") and (FD == 3)'
+)
+EXPR_client=(
+ '(TYPE == "UDP") and (FD == 4)'
+ '(TYPE == "UDP-Lite") and (FD == 4)'
+)
+COLNS=(
+ 'UDP'
+ 'UDPLite'
+)
+NAME=
+LADDR=
+LPORT=
+
+for lite in 0 1; do
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ server-do-bind=no \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR_server[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ NAME=$(${TS_CMD_LSFD} -n \
+ --raw \
+ -o NAME \
+ -p "${PID}" -Q "${EXPR_server[$lite]}")
+ if [[ "$NAME" =~ ^socket:\[[[:digit:]]+\]$ ]]; then
+ echo "NAME pattern match: OK"
+ else
+ echo "NAME pattern match: FAILED (NAME=$NAME)"
+ fi
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ client-do-bind=no \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR_client[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ LADDR=$(${TS_CMD_LSFD} -n \
+ --raw \
+ -o ${COLNS[$lite]}.LADDR \
+ -p "${PID}" -Q "${EXPR_client[$lite]}")
+ LPORT=$(${TS_CMD_LSFD} -n \
+ --raw \
+ -o ${COLNS[$lite]}.LPORT \
+ -p "${PID}" -Q "${EXPR_client[$lite]}")
+
+ if [[ 127.0.0.1:$LPORT == ${LADDR} ]]; then
+ echo "LADDR/LPORT pattern match: OK"
+ else
+ echo "LADDR/LPORT pattern match: FAILED (LADDR=$LADDR, LPORT=$LPORT)"
+ fi
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ client-do-connect=no \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,UDP.LADDR,UDP.LPORT,UDP.RADDR,UDP.RPORT \
+ -p "${PID}" -Q "${EXPR[$lite]}"
+ echo 'ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET.LADDR,INET.RADDR,UDP.LADDR,UDP.LPORT,UDP.RADDR,UDP.RPORT': $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+done > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-udp6 b/tests/ts/lsfd/mkfds-udp6
new file mode 100755
index 0000000..75381ba
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-udp6
@@ -0,0 +1,139 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="UDP6 and UDPLITEv6 sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_native_byteorder
+ts_skip_docker
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDS=3
+FDC=4
+EXPR=(
+ '(TYPE == "UDPv6") and (FD >= 3) and (FD <= 4)'
+ '(TYPE == "UDPLITEv6") and (FD >= 3) and (FD <= 4)'
+)
+EXPR_server=(
+ '(TYPE == "UDPv6") and (FD == 3)'
+ '(TYPE == "UDPLITEv6") and (FD == 3)'
+)
+EXPR_client=(
+ '(TYPE == "UDPv6") and (FD == 4)'
+ '(TYPE == "UDPLITEv6") and (FD == 4)'
+)
+COLNS=(
+ 'UDP'
+ 'UDPLite'
+ )
+NAME=
+LADDR=
+LPORT=
+
+for lite in 0 1; do
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp6 $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp6 $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ server-do-bind=no \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR_server[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ NAME=$(${TS_CMD_LSFD} -n \
+ --raw \
+ -o NAME \
+ -p "${PID}" -Q "${EXPR_server[$lite]}")
+ if [[ "$NAME" =~ ^socket:\[[[:digit:]]+\]$ ]]; then
+ echo "NAME pattern match: OK"
+ else
+ echo "NAME pattern match: FAILED (NAME=$NAME)"
+ fi
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp6 $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ client-do-bind=no \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR_client[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ LADDR=$(${TS_CMD_LSFD} -n \
+ --raw \
+ -o ${COLNS[$lite]}.LADDR \
+ -p "${PID}" -Q "${EXPR_client[$lite]}")
+ LPORT=$(${TS_CMD_LSFD} -n \
+ --raw \
+ -o ${COLNS[$lite]}.LPORT \
+ -p "${PID}" -Q "${EXPR_client[$lite]}")
+
+ if [[ '[::1]':$LPORT == "${LADDR}" ]]; then
+ echo "LADDR/LPORT pattern match: OK"
+ else
+ echo "LADDR/LPORT pattern match: FAILED (LADDR=$LADDR, LPORT=$LPORT)"
+ fi
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" udp6 $FDS $FDC \
+ server-port=34567 \
+ client-port=23456 \
+ client-do-connect=no \
+ lite=$lite; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT \
+ -p "${PID}" -Q "${EXPR[$lite]}"
+ echo "ASSOC,TYPE,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,INET6.LADDR,INET6.RADDR,${COLNS[$lite]}.LADDR,${COLNS[$lite]}.LPORT,${COLNS[$lite]}.RADDR,${COLNS[$lite]}.RPORT": $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+done > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-unix-dgram b/tests/ts/lsfd/mkfds-unix-dgram
new file mode 100755
index 0000000..c8b40eb
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-unix-dgram
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="UNIX dgram sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF/lsfd-functions.bash"
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDS=3
+FDC=4
+EXPR='(TYPE == "UNIX") and ((FD == 3) or (FD == 4))'
+
+make_state_connected()
+{
+ # The first one is for rewriting NAME column.
+ # The second one is for rewriting STATE column.
+ lsfd_make_state_connected | sed -e 's/unconnected/ connected/'
+}
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-dgram $FDS $FDC \
+ path=test_mkfds-unix-dgram ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | make_state_connected
+ echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-dgram $FDS $FDC \
+ path=test_mkfds-unix-dgram \
+ abstract=true ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | make_state_connected
+ echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': $?
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-unix-in-netns b/tests/ts/lsfd/mkfds-unix-in-netns
new file mode 100755
index 0000000..cfca087
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-unix-in-netns
@@ -0,0 +1,109 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="UNIX sockets made in a differenct net namespace"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+
+. "$TS_SELF/lsfd-functions.bash"
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDSELFNS=3
+FDALTNS=4
+FDSOCK=5
+
+EXPR='((TYPE == "UNIX") or (TYPE == "UNIX-STREAM")) and (FD == 5)'
+
+compare_net_namespaces()
+{
+ local type=$1
+ local pid=$2
+ local altns_inode
+ local sock_netns
+
+ altns_inode=$(${TS_CMD_LSFD} -n -o INODE -p "${pid}" -Q '(FD == 4)')
+ sock_netns=$(${TS_CMD_LSFD} -n -o SOCK.NETNS -p "${pid}" -Q '(FD == 5)')
+
+ if [[ "${altns_inode}" == "${sock_netns}" ]]; then
+ echo "the netns for the $type socket is extracted as expectedly"
+ else
+ echo "the netns for the $type socket is not extracted well"
+ echo "altns_inode=${altns_inode}"
+ echo "sock_netns=${sock_netns}"
+ fi
+}
+
+strip_type_stream()
+{
+ if [ "$1" = stream ]; then
+ lsfd_strip_type_stream
+ else
+ cat
+ fi
+}
+
+for t in stream dgram seqpacket; do
+ ts_init_subtest "$t"
+ {
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-in-netns $FDSELFNS $FDALTNS $FDSOCK \
+ path=test_mkfds-unix-$t-ns \
+ type=$t ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | strip_type_stream $t
+ echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+
+ compare_net_namespaces "$t" "${PID}"
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-in-netns $FDSELFNS $FDALTNS $FDSOCK \
+ path=test_mkfds-unix-$t-ns \
+ abstract=true \
+ type=$t ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | strip_type_stream $t
+ echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+
+ compare_net_namespaces "abstract $t" "${PID}"
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+ } > "$TS_OUTPUT" 2>&1
+ if [ "$?" == "$EPERM" ]; then
+ ts_skip_subtest "unshare(2) is not permitted on this platform"
+ continue
+ fi
+ ts_finalize_subtest
+done
+
+
+ts_finalize
diff --git a/tests/ts/lsfd/mkfds-unix-stream b/tests/ts/lsfd/mkfds-unix-stream
new file mode 100755
index 0000000..fe08e72
--- /dev/null
+++ b/tests/ts/lsfd/mkfds-unix-stream
@@ -0,0 +1,98 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="UNIX stream sockets"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF/lsfd-functions.bash"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+PID=
+FDS=3
+FDC=4
+FDA=5
+EXPR='(((TYPE == "UNIX-STREAM") or (TYPE == "UNIX")) and (FD >= 3) and (FD <= 5))'
+
+{
+ for t in stream seqpacket; do
+ # TYPE is not tested here; AF_UNIX+SOCK_STREAM socket type was changed from "UNIX"
+ # to "UNIX-STREAM" at a time in Linux kernel development history.
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-stream $FDS $FDC $FDA \
+ path=test_mkfds-unix-${t} \
+ type=$t ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | lsfd_strip_type_stream
+ echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-stream $FDS $FDC $FDA \
+ path=test_mkfds-unix-${t}-abs \
+ abstract=true ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | lsfd_strip_type_stream
+ echo '(abs) ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-stream $FDS $FDC $FDA \
+ path=test_mkfds-unix-${t}-shutdown \
+ server-shutdown=3 \
+ client-shutdown=3 \
+ type=$t ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | lsfd_strip_type_stream
+ echo '(shutdown) ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+ # Surprisingly, the socket status doesn't change at all.
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ coproc MKFDS { "$TS_HELPER_MKFDS" unix-stream $FDS $FDC $FDA \
+ path="test_mkfds-unix with spaces ${t}" \
+ type=$t ; }
+ if read -r -u "${MKFDS[0]}" PID; then
+ ${TS_CMD_LSFD} -n \
+ -o ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH \
+ -p "${PID}" -Q "${EXPR}" | lsfd_strip_type_stream
+ echo 'ASSOC,STTYPE,NAME,SOCK.STATE,SOCK.TYPE,SOCK.LISTENING,UNIX.PATH': ${PIPESTATUS[0]}
+
+ kill -CONT "${PID}"
+ fi
+ wait "${MKFDS_PID}"
+
+ done
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/option-filter-broken-exp b/tests/ts/lsfd/option-filter-broken-exp
new file mode 100755
index 0000000..bedf439
--- /dev/null
+++ b/tests/ts/lsfd/option-filter-broken-exp
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="passing broken expressions to -Q option"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ $TS_CMD_LSFD -Q ''
+ $TS_CMD_LSFD -Q '('
+ $TS_CMD_LSFD -Q ')'
+ $TS_CMD_LSFD -Q '(FD == 1)garbage'
+ $TS_CMD_LSFD -Q 'FD'
+ $TS_CMD_LSFD -Q 'NOSUCHCOLUMN'
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/option-inet b/tests/ts/lsfd/option-inet
new file mode 100755
index 0000000..011a9b3
--- /dev/null
+++ b/tests/ts/lsfd/option-inet
@@ -0,0 +1,98 @@
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="--inet option"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_qemu_user
+ts_skip_docker
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ "$TS_HELPER_MKFDS" -q tcp 3 4 5 server-port=34567 client-port=23456 &
+ PID0=$!
+
+ "$TS_HELPER_MKFDS" -q tcp6 3 4 5 server-port=34567 client-port=23456 &
+ PID1=$!
+
+ "$TS_HELPER_MKFDS" -q ro-regular-file 3 file=/etc/passwd &
+ PID2=$!
+
+ "$TS_HELPER_MKFDS" -q udp 3 4 server-port=34567 client-port=23456 server-do-bind=1 client-do-bind=1 client-do-connect=1&
+ PID3=$!
+
+ "$TS_HELPER_MKFDS" -q udp6 3 4 lite=1 server-port=34567 client-port=23456 server-do-bind=1 client-do-bind=1 client-do-connect=1&
+ PID4=$!
+
+ OPT='--inet'
+ echo "# $OPT"
+ ${TS_CMD_LSFD} -n \
+ $OPT \
+ -o ASSOC,TYPE,NAME \
+ -Q "(PID == $PID0) or (PID == $PID1) or (PID == $PID2) or (PID == $PID3) or (PID == $PID4)"
+
+ OPT='--inet=4'
+ echo "# $OPT"
+ ${TS_CMD_LSFD} -n \
+ $OPT \
+ -o ASSOC,TYPE,NAME \
+ -Q "(PID == $PID0) or (PID == $PID1) or (PID == $PID2) or (PID == $PID3) or (PID == $PID4)"
+
+ OPT='--inet=6'
+ echo "# $OPT"
+ ${TS_CMD_LSFD} -n \
+ $OPT \
+ -o ASSOC,TYPE,NAME \
+ -Q "(PID == $PID0) or (PID == $PID1) or (PID == $PID2) or (PID == $PID3) or (PID == $PID4)"
+
+ OPT='-i'
+ echo "# $OPT"
+ ${TS_CMD_LSFD} -n \
+ $OPT \
+ -o ASSOC,TYPE,NAME \
+ -Q "(PID == $PID0) or (PID == $PID1) or (PID == $PID2) or (PID == $PID3) or (PID == $PID4)"
+
+ OPT='-i4'
+ echo "# $OPT"
+ ${TS_CMD_LSFD} -n \
+ $OPT \
+ -o ASSOC,TYPE,NAME \
+ -Q "(PID == $PID0) or (PID == $PID1) or (PID == $PID2) or (PID == $PID3) or (PID == $PID4)"
+
+ OPT='-i6'
+ echo "# $OPT"
+ ${TS_CMD_LSFD} -n \
+ $OPT \
+ -o ASSOC,TYPE,NAME \
+ -Q "(PID == $PID0) or (PID == $PID1) or (PID == $PID2) or (PID == $PID3) or (PID == $PID4)"
+
+ kill -CONT "${PID0}"
+ wait "${PID0}"
+
+ kill -CONT "${PID1}"
+ wait "${PID1}"
+
+ kill -CONT "${PID2}"
+ wait "${PID2}"
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/option-pid b/tests/ts/lsfd/option-pid
new file mode 100755
index 0000000..0ea4353
--- /dev/null
+++ b/tests/ts/lsfd/option-pid
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="--pid option"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+ts_skip_nonroot
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_prog "ps"
+
+ts_cd "$TS_OUTDIR"
+
+[ "$(ps --no-headers -o comm 1)" = 'systemd' ] || ts_skip "pid 1 is not systemd"
+
+PID=
+FD=3
+EXPR=
+QOUT=
+POUT=
+
+{
+ coproc MKFDS { "$TS_HELPER_MKFDS" ro-regular-file $FD file=/etc/group; }
+ if read -u ${MKFDS[0]} PID; then
+ EXPR='((PID == '"${PID}"') or (PID == 1)) and (FD == '"$FD"')'
+ QOUT=$(${TS_CMD_LSFD} -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "${EXPR}")
+ echo "QOUT:" $?
+
+ POUT=$(${TS_CMD_LSFD} --pid="1 $PID" -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "(FD == $FD)")
+ echo "POUT[--pid=1 PID]:" $?
+ [ "${QOUT}" = "${POUT}" ]
+ echo "EQ[--pid=1 PID]:" $?
+
+ POUT=$(${TS_CMD_LSFD} --pid="$PID 1" -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "(FD == $FD)")
+ echo "POUT[--pid=PID 1]:" $?
+ [ "${QOUT}" = "${POUT}" ]
+ echo "EQ[--pid=PID 1]:" $?
+
+ POUT=$(${TS_CMD_LSFD} --pid="1,$PID" -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "(FD == $FD)")
+ echo "POUT[--pid=1,PID]:" $?
+ [ "${QOUT}" = "${POUT}" ]
+ echo "EQ[--pid=1,PID]:" $?
+
+ POUT=$(${TS_CMD_LSFD} --pid="$PID,1" -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "(FD == $FD)")
+ echo "POUT[--pid=PID,1]:" $?
+ [ "${QOUT}" = "${POUT}" ]
+ echo "EQ[--pid=PID,1]:" $?
+
+ POUT=$(${TS_CMD_LSFD} -p 1 --pid="$PID" -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "(FD == $FD)")
+ echo "POUT[-p 1 --pid=PID]:" $?
+ [ "${QOUT}" = "${POUT}" ]
+ echo "EQ[-p 1 --pid=PID]:" $?
+
+ POUT=$(${TS_CMD_LSFD} -p "$PID" --pid=1 -n -o ASSOC,MODE,TYPE,FLAGS,NAME -Q "(FD == $FD)")
+ echo "POUT[-p PID --pid=1]:" $?
+ [ "${QOUT}" = "${POUT}" ]
+ echo "EQ[-p PID --pid=1]:" $?
+
+ kill -CONT ${PID}
+ fi
+ wait ${MKFDS_PID}
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
diff --git a/tests/ts/lsfd/option-summary b/tests/ts/lsfd/option-summary
new file mode 100755
index 0000000..64bf54b
--- /dev/null
+++ b/tests/ts/lsfd/option-summary
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="--summary option"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+. "$TS_SELF"/lsfd-functions.bash
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_test_command "$TS_HELPER_MKFDS"
+ts_check_prog "ps"
+
+ts_cd "$TS_OUTDIR"
+
+FD=3
+F_GROUP=/etc/group
+F_PASSWD=/etc/passwd
+PIDS=
+PID=
+
+for i in {1..10}; do
+ "$TS_HELPER_MKFDS" -q ro-regular-file $FD file=$F_GROUP &
+ PID=$!
+ PIDS="${PIDS} ${PID} "
+ lsfd_wait_for_pausing "${PID}"
+done
+
+for i in {1..3}; do
+ "$TS_HELPER_MKFDS" -q ro-regular-file $FD file=$F_PASSWD &
+ PID=$!
+ PIDS="${PIDS} ${PID} "
+ lsfd_wait_for_pausing "${PID}"
+done
+
+${TS_CMD_LSFD} -n --summary=only \
+ --pid="${PIDS}" \
+ --counter=GROUP:'(NAME == "/etc/group")' \
+ --counter=PASSWD:'(NAME == "/etc/passwd")' \
+ --counter=PROC:'(ASSOC == "exe")' \
+ > $TS_OUTPUT 2>&1
+
+for PID in ${PIDS}; do
+ kill -CONT "${PID}"
+done
+
+ts_finalize