From: Masatake YAMATO Date: Thu, 4 Aug 2022 15:48:15 +0000 (+0900) Subject: lsfd: show pids targeted by pidfds in NAME column X-Git-Tag: v2.39-rc1~550^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ba8c749fa54780a7d64bdb89f53ee9893b171401;p=thirdparty%2Futil-linux.git lsfd: show pids targeted by pidfds in NAME column 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 --- diff --git a/misc-utils/lsfd-unkn.c b/misc-utils/lsfd-unkn.c index 34038e2b9a..876e7f1288 100644 --- a/misc-utils/lsfd-unkn.c +++ b/misc-utils/lsfd-unkn.c @@ -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 index 0000000000..b962000157 --- /dev/null +++ b/tests/expected/lsfd/mkfds-pidfd @@ -0,0 +1,2 @@ + 3 UNKN anon_inodefs pidfd: pid=1 comm=systemd nspid=1 +ASSOC,TYPE,SOURCE,NAME: 0 diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index e0a7ea8677..1f16d1d682 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -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 index 0000000000..112e478fcf --- /dev/null +++ b/tests/ts/lsfd/mkfds-pidfd @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Copyright (C) 2022 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="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