From e467c18c7acaece7a871506ca699cab262c0026e Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sat, 31 Jan 2026 05:27:02 +0900 Subject: [PATCH] lsfd: add new association "pidfs" This new association is inspired by the getino command. Output example: $ ./lsfd --pid=1 -Q '(ASSOC == "pidfs")' COMMAND PID USER ASSOC XMODE TYPE SOURCE MNTID INODE NAME systemd 1 root pidfs ------ pidfd anon_inodefs 5 2 pid=1 comm=systemd nspid=1 Signed-off-by: Masatake YAMATO --- lsfd-cmd/file.c | 1 + lsfd-cmd/lsfd.c | 52 +++++++++++++++++++++++ lsfd-cmd/lsfd.h | 4 +- tests/expected/lsfd/assoc-pidfs | 4 ++ tests/ts/lsfd/assoc-pidfs | 75 +++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/expected/lsfd/assoc-pidfs create mode 100755 tests/ts/lsfd/assoc-pidfs diff --git a/lsfd-cmd/file.c b/lsfd-cmd/file.c index 41642224b..dea556247 100644 --- a/lsfd-cmd/file.c +++ b/lsfd-cmd/file.c @@ -71,6 +71,7 @@ static const char *assocstr[N_ASSOCS] = { /* "root" appears as user names, too. * So we use "rtd" here instead of "root". */ [ASSOC_ROOT] = "rtd", + [ASSOC_PIDFS] = "pidfs", [ASSOC_NS_CGROUP] = "cgroup", [ASSOC_NS_IPC] = "ipc", [ASSOC_NS_MNT] = "mnt", diff --git a/lsfd-cmd/lsfd.c b/lsfd-cmd/lsfd.c index 1326082d5..39523fa24 100644 --- a/lsfd-cmd/lsfd.c +++ b/lsfd-cmd/lsfd.c @@ -55,6 +55,7 @@ #include "fileutils.h" #include "idcache.h" #include "pathnames.h" +#include "pidfd-utils.h" #include "lsfd.h" @@ -1105,6 +1106,55 @@ static void collect_execve_file(struct path_cxt *pc, struct proc *proc, sockets_only); } +static void collect_pidfs_file(struct proc *proc, bool sockets_only) +{ + struct file *f = NULL; + int pidfd; + + if (sockets_only) + return; + + pidfd = pidfd_open(proc->pid, 0); + if (pidfd < 0) + return; + + { + struct stat sb; + const int assoc = ASSOC_PIDFS * -1; + + if (fstat(pidfd, &sb) < 0) + goto out; + + if ((sb.st_mode & S_IFMT) == S_IFREG) { + char *name = NULL; + xasprintf(&name, "pidfd:[%llu]", (unsigned long long)sb.st_ino); + f = new_file(proc, &pidfs_file_class, &sb, name, assoc); + free(name); + } + else + f = new_file(proc, &unkn_class, &sb, "anon_inode:[pidfd]", assoc); + } + + file_init_content(f); + + { + char *fdinfo = NULL; + FILE *fdinfo_fp; + const pid_t lsfd_pid = getpid(); + + xasprintf(&fdinfo, "%s/%d/fdinfo/%d", _PATH_PROC, lsfd_pid, pidfd); + fdinfo_fp = fopen(fdinfo, "r"); + if (fdinfo_fp) { + read_fdinfo(f, fdinfo_fp); + fclose(fdinfo_fp); + } + free(fdinfo); + } + + out: + close(pidfd); +} + static void collect_fs_files(struct path_cxt *pc, struct proc *proc, bool sockets_only) { @@ -2038,6 +2088,8 @@ static void read_process(struct lsfd_control *ctl, struct path_cxt *pc, || kcmp(proc->leader->pid, proc->pid, KCMP_FS, 0, 0) != 0) collect_fs_files(pc, proc, ctl->sockets_only); + collect_pidfs_file(proc, ctl->sockets_only); + /* Reading /proc/$pid/mountinfo is expensive. * mnt_namespaces is a table for avoiding reading mountinfo files * for an identical mnt namespace. diff --git a/lsfd-cmd/lsfd.h b/lsfd-cmd/lsfd.h index a98bcbe3e..469e58bce 100644 --- a/lsfd-cmd/lsfd.h +++ b/lsfd-cmd/lsfd.h @@ -163,6 +163,7 @@ enum association { ASSOC_EXE = 1, ASSOC_CWD, ASSOC_ROOT, + ASSOC_PIDFS, ASSOC_NS_CGROUP, ASSOC_NS_IPC, ASSOC_NS_MNT, @@ -226,7 +227,8 @@ struct file { #define is_mapped_file(_f) (is_association((_f), SHM) || is_association((_f), MEM)) #define is_association(_f, a) ((_f)->association < 0 && (_f)->association == -ASSOC_ ## a) #define has_mnt_id(_f) (is_opened_file(_f) || is_mapped_file(_f) \ - || is_association(_f, EXE) || is_association(_f, CWD) || is_association(_f, ROOT)) + || is_association(_f, EXE) || is_association(_f, CWD) || is_association(_f, ROOT) \ + || is_association(_f, PIDFS)) struct file_class { const struct file_class *super; diff --git a/tests/expected/lsfd/assoc-pidfs b/tests/expected/lsfd/assoc-pidfs new file mode 100644 index 000000000..639544590 --- /dev/null +++ b/tests/expected/lsfd/assoc-pidfs @@ -0,0 +1,4 @@ +INODE: OK +PID: OK +COMM: OK +NSPID: OK diff --git a/tests/ts/lsfd/assoc-pidfs b/tests/ts/lsfd/assoc-pidfs new file mode 100755 index 000000000..238d6cad7 --- /dev/null +++ b/tests/ts/lsfd/assoc-pidfs @@ -0,0 +1,75 @@ +#!/bin/bash +# +# Copyright (C) 2026 Masatake YAMATO +# +# 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="pidfs association" + +. "$TS_TOPDIR"/functions.sh +ts_init "$*" + +ts_check_test_command "$TS_CMD_LSFD" +ts_check_test_command "$TS_CMD_GETINO" +ts_check_test_command "$TS_HELPER_MKFDS" + +ts_cd "$TS_OUTDIR" + +PID= +INODE= +{ + coproc MKFDS { "$TS_HELPER_MKFDS" nop; } + if read -u ${MKFDS[0]} PID; then + INODE=$("$TS_CMD_GETINO" "$PID") + inode=$(${TS_CMD_LSFD} --pid="$PID" -n -o INODE -Q '(ASSOC == "pidfs")') + if [[ -z "$inode" ]]; then + echo INODE: "FAILED (empty)" + elif [[ "$inode" == "$INODE" ]]; then + echo INODE: OK + else + echo INODE: "FAILED (getino: $INODE, lsfd: $inode)" + fi + + pid=$(${TS_CMD_LSFD} --pid="$PID" -n -o PIDFD.PID -Q '(ASSOC == "pidfs")') + if [[ -z "$pid" ]]; then + echo PID: "FAILED (empty)" + elif [[ "$pid" == "$PID" ]]; then + echo PID: OK + else + echo PID: "FAILED (PID: $PID, lsfd: $pid)" + fi + + comm=$(${TS_CMD_LSFD} --pid="$PID" -n -o PIDFD.COMM -Q '(ASSOC == "pidfs")') + if [[ "$comm" =~ .*test_mkfds ]]; then + echo COMM: OK + else + echo COMM: "FAILED (lsfd: $comm)" + fi + + nspid=$(${TS_CMD_LSFD} --pid="$PID" -n -o PIDFD.NSPID -Q '(ASSOC == "pidfs")') + if [[ -z "$nspid" ]]; then + echo NSPID: "FAILED (empty)" + elif [[ "$nspid" == "$PID" ]]; then + echo NSPID: OK + else + echo NSPID: "FAILED (PID: $PID, lsfd: $nspid)" + fi + + echo DONE >&"${MKFDS[1]}" + + fi + wait ${MKFDS_PID} +} > $TS_OUTPUT 2>&1 + +ts_finalize -- 2.47.3