]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: show pids targeted by pidfds in NAME column
authorMasatake YAMATO <yamato@redhat.com>
Thu, 4 Aug 2022 15:48:15 +0000 (00:48 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Mon, 8 Aug 2022 20:52:46 +0000 (05:52 +0900)
Example output:

  $ sudo ./lsfd -Q '(NAME =~ "pidfd: .*")'
  COMMAND           PID  ... TYPE       SOURCE ... NAME
  dbus-broker-lau  1010  ... UNKN anon_inodefs ... pidfd: pid=1015 comm=dbus-broker nspid=1015
  dbus-broker-lau 14786  ... UNKN anon_inodefs ... pidfd: pid=14788 comm=dbus-broker nspid=14788
  dbus-broker-lau 15051  ... UNKN anon_inodefs ... pidfd: pid=15053 comm=dbus-broker nspid=15053

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
misc-utils/lsfd-unkn.c
tests/expected/lsfd/mkfds-pidfd [new file with mode: 0644]
tests/helpers/test_mkfds.c
tests/ts/lsfd/mkfds-pidfd [new file with mode: 0755]

index 34038e2b9a941c9d9165bfc9761052a09243267b..876e7f12889f44b1288eb9b26b4681c2a9c7736c 100644 (file)
@@ -39,6 +39,7 @@ struct anon_ops {
 };
 
 static struct anon_ops anon_generic_ops;
+static struct anon_ops anon_pidfd_ops;
 
 static bool unkn_fill_column(struct proc *proc __attribute__((__unused__)),
                             struct file *file,
@@ -88,7 +89,13 @@ static void unkn_init_content(struct file *file)
 
        if (major(file->stat.st_dev) == 0
            && strncmp(file->name, "anon_inode:", 11) == 0) {
-               unkn->anon_ops = &anon_generic_ops;
+               const char *rest = file->name + 11;
+
+               if (strncmp(rest, "[pidfd]", 7) == 0)
+                       unkn->anon_ops = &anon_pidfd_ops;
+               else
+                       unkn->anon_ops = &anon_generic_ops;
+
                if (unkn->anon_ops->init)
                        unkn->anon_ops->init(unkn);
        }
@@ -113,6 +120,71 @@ static int unkn_handle_fdinfo(struct file *file, const char *key, const char *va
        return 0;               /* Should be handled in parents */
 }
 
+/*
+ * pidfd
+ */
+struct anon_pidfd_data {
+       pid_t pid;
+       char *nspid;
+};
+
+static char *anon_pidfd_get_name(struct unkn *unkn)
+{
+       char *str = NULL;
+       struct anon_pidfd_data *data = (struct anon_pidfd_data *)unkn->anon_data;
+
+       char *comm = NULL;
+       struct proc *proc = get_proc(data->pid);
+       if (proc)
+               comm = proc->command;
+
+       xasprintf(&str, "pidfd: pid=%d comm=%s nspid=%s",
+                 data->pid,
+                 comm? comm: "",
+                 data->nspid? data->nspid: "");
+       return str;
+}
+
+static void anon_pidfd_init(struct unkn *unkn)
+{
+       unkn->anon_data = xcalloc(1, sizeof(struct anon_pidfd_data));
+}
+
+static void anon_pidfd_free(struct unkn *unkn)
+{
+       struct anon_pidfd_data *data = (struct anon_pidfd_data *)unkn->anon_data;
+
+       if (data->nspid)
+               free(data->nspid);
+       free(data);
+}
+
+static int anon_pidfd_handle_fdinfo(struct unkn *unkn, const char *key, const char *value)
+{
+       if (strcmp(key, "Pid") == 0) {
+               uint64_t pid;
+
+               int rc = ul_strtou64(value, &pid, 10);
+               if (rc < 0)
+                       return 0; /* ignore -- parse failed */
+               ((struct anon_pidfd_data *)unkn->anon_data)->pid = (pid_t)pid;
+               return 1;
+       }
+       else if (strcmp(key, "NSpid") == 0) {
+               ((struct anon_pidfd_data *)unkn->anon_data)->nspid = xstrdup(value);
+               return 1;
+
+       }
+       return 0;
+}
+
+static struct anon_ops anon_pidfd_ops = {
+       .get_name = anon_pidfd_get_name,
+       .init = anon_pidfd_init,
+       .free = anon_pidfd_free,
+       .handle_fdinfo = anon_pidfd_handle_fdinfo,
+};
+
 /*
  * generic (fallback implementation)
  */
diff --git a/tests/expected/lsfd/mkfds-pidfd b/tests/expected/lsfd/mkfds-pidfd
new file mode 100644 (file)
index 0000000..b962000
--- /dev/null
@@ -0,0 +1,2 @@
+    3 UNKN anon_inodefs pidfd: pid=1 comm=systemd nspid=1
+ASSOC,TYPE,SOURCE,NAME: 0
index e0a7ea86778b4eecfb2667d52c65e308438a08b5..1f16d1d68200cddb9db4c7cbd5110508b86bd3cd 100644 (file)
@@ -34,6 +34,7 @@
 #include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <sys/user.h>
@@ -45,6 +46,8 @@
 
 #define _U_ __attribute__((__unused__))
 
+static int pidfd_open(pid_t pid, unsigned int flags);
+
 static void __attribute__((__noreturn__)) usage(FILE *out, int status)
 {
        fputs(USAGE_HEADER, out);
@@ -666,6 +669,34 @@ static void make_mmapped_packet_socket(const struct factory *factory, struct fde
        };
 }
 
+static void make_pidfd(const struct factory *factory, struct fdesc fdescs[], pid_t * child _U_,
+                      int argc, char ** argv)
+{
+       struct arg target_pid = decode_arg("target-pid", factory->params, argc, argv);
+       pid_t pid = ARG_INTEGER(target_pid);
+
+       int fd = pidfd_open(pid, 0);
+       if (fd < 0)
+               err(EXIT_FAILURE, "failed in pidfd_open(%d)", (int)pid);
+       free_arg(&target_pid);
+
+       if (fd != fdescs[0].fd) {
+               if (dup2(fd, fdescs[0].fd) < 0) {
+                       int e = errno;
+                       close(fd);
+                       errno = e;
+                       err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
+               }
+               close(fd);
+       }
+
+       fdescs[0] = (struct fdesc){
+               .fd    = fdescs[0].fd,
+               .close = close_fdesc,
+               .data  = NULL
+       };
+}
+
 #define PARAM_END { .name = NULL, }
 static const struct factory factories[] = {
        {
@@ -842,6 +873,25 @@ static const struct factory factories[] = {
                        PARAM_END
                },
        },
+       {
+
+               .name = "pidfd",
+               .desc = "pidfd returned from pidfd_open(2)",
+               .priv = false,
+               .N    = 1,
+               .EX_N = 0,
+               .fork = false,
+               .make = make_pidfd,
+               .params = (struct parameter []) {
+                       {
+                               .name = "target-pid",
+                               .type = PTYPE_INTEGER,
+                               .desc = "the pid of the target process",
+                               .defv.integer = 1,
+                       },
+                       PARAM_END
+               },
+       },
 };
 
 static int count_parameters(const struct factory *factory)
@@ -910,6 +960,22 @@ static void do_nothing(int signum _U_)
 {
 }
 
+#ifdef __NR_pidfd_open
+
+static int
+pidfd_open(pid_t pid, unsigned int flags)
+{
+       return syscall(__NR_pidfd_open, pid, flags);
+}
+#else
+static int
+pidfd_open(pid_t pid _U_, unsigned int flags _U_)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
+
 int main(int argc, char **argv)
 {
        int c;
diff --git a/tests/ts/lsfd/mkfds-pidfd b/tests/ts/lsfd/mkfds-pidfd
new file mode 100755 (executable)
index 0000000..112e478
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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_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)"
+
+{
+    coproc MKFDS { "$TS_HELPER_MKFDS" pidfd $FD target-pid=${TARGET} ; }
+    if read -u ${MKFDS[0]} PID; then
+       ${TS_CMD_LSFD} -n -o ASSOC,TYPE,SOURCE,NAME -p "${PID}" -p ${TARGET} -Q "${EXPR}"
+       echo 'ASSOC,TYPE,SOURCE,NAME': $?
+
+       kill -CONT ${PID}
+       wait ${MKFDS_PID}
+    fi
+} > $TS_OUTPUT 2>&1
+
+ts_finalize