diff options
author | Karel Zak <kzak@redhat.com> | 2024-04-08 09:48:10 +0200 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2024-04-08 09:48:10 +0200 |
commit | 44b92ef3bb950f5680c5febcca5d4b47e67c628c (patch) | |
tree | b6137d6b7fb6f37cda0338ebb985543f5260a96d | |
parent | df72ff49ed5dabb388c4a7c914c272ffd4264471 (diff) | |
parent | 04db2ba9008e9635286b1aafc8ecd9533a0a91bf (diff) | |
download | util-linux-44b92ef3bb950f5680c5febcca5d4b47e67c628c.tar.gz |
Merge branch 'xry111/pidfs' of https://github.com/xry111/util-linux
* 'xry111/pidfs' of https://github.com/xry111/util-linux:
lsfd: test: Adapt test cases for pidfs
lsfd: Support pidfs
lsfd: Refactor the pidfd logic into lsfd-pidfd.c
include: Include <unistd.h> in pidfd-utils.h for syscall()
-rw-r--r-- | include/pidfd-utils.h | 1 | ||||
-rw-r--r-- | misc-utils/Makemodule.am | 4 | ||||
-rw-r--r-- | misc-utils/lsfd-file.c | 96 | ||||
-rw-r--r-- | misc-utils/lsfd-pidfd.c | 95 | ||||
-rw-r--r-- | misc-utils/lsfd-pidfd.h | 37 | ||||
-rw-r--r-- | misc-utils/lsfd-unkn.c | 71 | ||||
-rw-r--r-- | misc-utils/lsfd.c | 3 | ||||
-rw-r--r-- | misc-utils/lsfd.h | 7 | ||||
-rw-r--r-- | misc-utils/meson.build | 1 | ||||
-rw-r--r-- | tests/expected/lsfd/column-name-pidfd | 2 | ||||
-rw-r--r-- | tests/expected/lsfd/column-type-pidfd | 2 | ||||
-rw-r--r-- | tests/expected/lsfd/mkfds-pidfd | 2 | ||||
-rwxr-xr-x | tests/ts/lsfd/column-ainodeclass | 8 | ||||
-rwxr-xr-x | tests/ts/lsfd/column-name | 7 | ||||
-rwxr-xr-x | tests/ts/lsfd/column-type | 7 | ||||
-rwxr-xr-x | tests/ts/lsfd/mkfds-pidfd | 4 |
16 files changed, 282 insertions, 65 deletions
diff --git a/include/pidfd-utils.h b/include/pidfd-utils.h index ff0bc4c792..0ee55f3bac 100644 --- a/include/pidfd-utils.h +++ b/include/pidfd-utils.h @@ -7,6 +7,7 @@ #ifdef HAVE_SYS_SYSCALL_H # include <sys/syscall.h> +# include <unistd.h> /* * If the kernel headers are too old to provide the syscall numbers, let's diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am index 9edf3d98ed..7622a5d7be 100644 --- a/misc-utils/Makemodule.am +++ b/misc-utils/Makemodule.am @@ -298,7 +298,9 @@ lsfd_SOURCES = \ misc-utils/lsfd-sock.h \ misc-utils/lsfd-sock-xinfo.c \ misc-utils/lsfd-unkn.c \ - misc-utils/lsfd-fifo.c + misc-utils/lsfd-fifo.c \ + misc-utils/lsfd-pidfd.h \ + misc-utils/lsfd-pidfd.c lsfd_LDADD = $(LDADD) $(MQ_LIBS) libsmartcols.la libcommon.la lsfd_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) endif diff --git a/misc-utils/lsfd-file.c b/misc-utils/lsfd-file.c index 7287a1de83..35eabb3e45 100644 --- a/misc-utils/lsfd-file.c +++ b/misc-utils/lsfd-file.c @@ -45,6 +45,8 @@ #include "procfs.h" #include "lsfd.h" +#include "lsfd-pidfd.h" +#include "pidfd-utils.h" static size_t pagesize; @@ -653,6 +655,22 @@ static unsigned long get_minor_for_mqueue(void) return minor(sb.st_dev); } +static unsigned long get_minor_for_pidfs(void) +{ + int fd = pidfd_open(getpid(), 0); + struct stat sb; + unsigned long ret = 0; + + if (fd < 0) + return 0; + + if (fstat(fd, &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFREG) + ret = minor(sb.st_dev); + + close(fd); + return ret; +} + static void file_class_initialize(void) { unsigned long m; @@ -667,6 +685,10 @@ static void file_class_initialize(void) m = get_minor_for_mqueue(); if (m) add_nodev(m, "mqueue"); + + m = get_minor_for_pidfs(); + if (m) + add_nodev(m, "pidfs"); } const struct file_class file_class = { @@ -935,3 +957,77 @@ const struct file_class mqueue_file_class = { .fill_column = mqueue_file_fill_column, .get_ipc_class = mqueue_file_get_ipc_class, }; + +struct pidfs_file { + struct file file; + struct pidfd_data data; +}; + +static void init_pidfs_file_content(struct file *file) +{ + struct pidfs_file *pidfs_file = (struct pidfs_file *)file; + + memset(&pidfs_file->data, 0, sizeof(pidfs_file->data)); +} + +static int pidfs_file_handle_fdinfo(struct file *file, const char *key, const char *value) +{ + struct pidfs_file *pidfs_file = (struct pidfs_file *)file; + + return pidfd_handle_fdinfo(&pidfs_file->data, key, value); +} + +static void pidfs_file_free_content(struct file *file) +{ + struct pidfs_file *pidfs_file = (struct pidfs_file *)file; + + pidfd_free(&pidfs_file->data); +} + +static bool pidfs_file_fill_column(struct proc *proc __attribute__((__unused__)), + struct file *file, + struct libscols_line *ln, + int column_id, + size_t column_index) +{ + struct pidfs_file *pidfs_file = (struct pidfs_file *)file; + char *buf = NULL; + + switch(column_id) { + case COL_TYPE: + if (scols_line_set_data(ln, column_index, "pidfd")) + err(EXIT_FAILURE, _("failed to add output data")); + return true; + case COL_NAME: + buf = pidfd_get_name(&pidfs_file->data); + break; + default: + if (!pidfd_fill_column(&pidfs_file->data, column_id, &buf)) + return false; + } + + if (buf && + scols_line_refer_data(ln, column_index, buf)) + err(EXIT_FAILURE, _("failed to add output data")); + + return true; +} + +const struct file_class pidfs_file_class = { + .super = &file_class, + .size = sizeof(struct pidfs_file), + .initialize_content = init_pidfs_file_content, + .handle_fdinfo = pidfs_file_handle_fdinfo, + .fill_column = pidfs_file_fill_column, + .free_content = pidfs_file_free_content, +}; + +bool is_pidfs_dev(dev_t dev) +{ + const char *fs = get_nodev_filesystem(minor(dev)); + + if (fs && (strcmp (fs, "pidfs") == 0)) + return true; + + return false; +} diff --git a/misc-utils/lsfd-pidfd.c b/misc-utils/lsfd-pidfd.c new file mode 100644 index 0000000000..430a8028dc --- /dev/null +++ b/misc-utils/lsfd-pidfd.c @@ -0,0 +1,95 @@ +/* + * lsfd-pidfd.c - handle pidfd (from anon_inode or pidfs) + * + * Copyright (C) 2024 Xi Ruoyao <xry111@xry111.site> + * + * Refactored and moved out from lsfd-unkn.c (originally authored by + * Masatake YAMATO <yamato@redhat.com>). + * + * This program 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 program is distributed in the hope that it would 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> + +#include "strutils.h" +#include "xalloc.h" + +#include "lsfd.h" +#include "lsfd-pidfd.h" + +int pidfd_handle_fdinfo(struct pidfd_data *data, 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 */ + + data->pid = (pid_t)pid; + return 1; + } else if (strcmp(key, "NSpid") == 0) { + data->nspid = xstrdup(value); + return 1; + } + + return 0; +} + +char *pidfd_get_name(struct pidfd_data *data) +{ + char *str = NULL; + char *comm = NULL; + struct proc *proc = get_proc(data->pid); + + if (proc) + comm = proc->command; + + xasprintf(&str, "pid=%d comm=%s nspid=%s", + data->pid, + comm ? comm : "", + data->nspid ? data->nspid : ""); + return str; +} + +bool pidfd_fill_column(struct pidfd_data *data, int column_id, char **str) +{ + switch(column_id) { + case COL_PIDFD_COMM: { + struct proc *pidfd_proc = get_proc(data->pid); + char *pidfd_comm = NULL; + + if (pidfd_proc) + pidfd_comm = pidfd_proc->command; + if (pidfd_comm) { + *str = xstrdup(pidfd_comm); + return true; + } + break; + } + case COL_PIDFD_NSPID: + if (data->nspid) { + *str = xstrdup(data->nspid); + return true; + } + break; + case COL_PIDFD_PID: + xasprintf(str, "%d", (int)data->pid); + return true; + } + + return false; +} diff --git a/misc-utils/lsfd-pidfd.h b/misc-utils/lsfd-pidfd.h new file mode 100644 index 0000000000..2f65d3b3f3 --- /dev/null +++ b/misc-utils/lsfd-pidfd.h @@ -0,0 +1,37 @@ +/* + * lsfd-pidfd.h - handle pidfd (from anon_inode or pidfs) + * + * Copyright (C) 2024 Xi Ruoyao <xry111@xry111.site> + * + * This program 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 program is distributed in the hope that it would 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdbool.h> +#include <sys/types.h> + +struct pidfd_data { + pid_t pid; + char *nspid; +}; + +int pidfd_handle_fdinfo(struct pidfd_data *, const char *, const char *); +char *pidfd_get_name(struct pidfd_data *); +bool pidfd_fill_column(struct pidfd_data *, int, char **); + +static inline void __attribute__((nonnull(1))) +pidfd_free(struct pidfd_data *data) +{ + free(data->nspid); +} diff --git a/misc-utils/lsfd-unkn.c b/misc-utils/lsfd-unkn.c index 8f6e908468..8e257f479b 100644 --- a/misc-utils/lsfd-unkn.c +++ b/misc-utils/lsfd-unkn.c @@ -28,6 +28,7 @@ #include "timeutils.h" #include "lsfd.h" +#include "lsfd-pidfd.h" #define offsetofend(TYPE, MEMBER) \ (offsetof(TYPE, MEMBER) + sizeof_member(TYPE, MEMBER)) @@ -183,10 +184,6 @@ static int unkn_handle_fdinfo(struct file *file, const char *key, const char *va /* * pidfd */ -struct anon_pidfd_data { - pid_t pid; - char *nspid; -}; static bool anon_pidfd_probe(const char *str) { @@ -195,51 +192,28 @@ static bool anon_pidfd_probe(const char *str) static char *anon_pidfd_get_name(struct unkn *unkn) { - char *str = NULL; - struct anon_pidfd_data *data = (struct anon_pidfd_data *)unkn->anon_data; + struct pidfd_data *data = (struct pidfd_data *)unkn->anon_data; - char *comm = NULL; - struct proc *proc = get_proc(data->pid); - if (proc) - comm = proc->command; - - xasprintf(&str, "pid=%d comm=%s nspid=%s", - data->pid, - comm? comm: "", - data->nspid? data->nspid: ""); - return str; + return pidfd_get_name(data); } static void anon_pidfd_init(struct unkn *unkn) { - unkn->anon_data = xcalloc(1, sizeof(struct anon_pidfd_data)); + unkn->anon_data = xcalloc(1, sizeof(struct pidfd_data)); } static void anon_pidfd_free(struct unkn *unkn) { - struct anon_pidfd_data *data = (struct anon_pidfd_data *)unkn->anon_data; + struct pidfd_data *data = (struct pidfd_data *)unkn->anon_data; - if (data->nspid) - free(data->nspid); + pidfd_free(data); 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; + return pidfd_handle_fdinfo((struct pidfd_data *)unkn->anon_data, + key, value); } static bool anon_pidfd_fill_column(struct proc *proc __attribute__((__unused__)), @@ -249,32 +223,9 @@ static bool anon_pidfd_fill_column(struct proc *proc __attribute__((__unused__) size_t column_index __attribute__((__unused__)), char **str) { - struct anon_pidfd_data *data = (struct anon_pidfd_data *)unkn->anon_data; - - switch(column_id) { - case COL_PIDFD_COMM: { - struct proc *pidfd_proc = get_proc(data->pid); - char *pidfd_comm = NULL; - if (pidfd_proc) - pidfd_comm = pidfd_proc->command; - if (pidfd_comm) { - *str = xstrdup(pidfd_comm); - return true; - } - break; - } - case COL_PIDFD_NSPID: - if (data->nspid) { - *str = xstrdup(data->nspid); - return true; - } - break; - case COL_PIDFD_PID: - xasprintf(str, "%d", (int)data->pid); - return true; - } - - return false; + return pidfd_fill_column((struct pidfd_data *)unkn->anon_data, + column_id, + str); } static const struct anon_ops anon_pidfd_ops = { diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index d4d2a99bc9..f042f5caaa 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -667,6 +667,9 @@ static const struct file_class *stat2class(struct stat *sb) if (is_mqueue_dev(dev)) return &mqueue_file_class; + if (is_pidfs_dev(dev)) + return &pidfs_file_class; + return &file_class; default: break; diff --git a/misc-utils/lsfd.h b/misc-utils/lsfd.h index b9a402ad20..217bf45338 100644 --- a/misc-utils/lsfd.h +++ b/misc-utils/lsfd.h @@ -220,7 +220,7 @@ struct file_class { extern const struct file_class abst_class, readlink_error_class, stat_error_class, file_class, cdev_class, bdev_class, sock_class, unkn_class, fifo_class, - nsfs_file_class, mqueue_file_class; + nsfs_file_class, mqueue_file_class, pidfs_file_class; /* * IPC @@ -299,4 +299,9 @@ bool is_mqueue_dev(dev_t dev); */ bool is_multiplexed_by_eventpoll(int fd, struct list_head *eventpolls); +/* + * Pidfs + */ +bool is_pidfs_dev(dev_t dev); + #endif /* UTIL_LINUX_LSFD_H */ diff --git a/misc-utils/meson.build b/misc-utils/meson.build index 847b1012cf..68ea9777ec 100644 --- a/misc-utils/meson.build +++ b/misc-utils/meson.build @@ -56,6 +56,7 @@ lsfd_sources = files ( 'lsfd-sock-xinfo.c', 'lsfd-unkn.c', 'lsfd-fifo.c', + 'lsfd-pidfd.c', ) uuidgen_sources = files( diff --git a/tests/expected/lsfd/column-name-pidfd b/tests/expected/lsfd/column-name-pidfd index 10e3c5e7f5..68787d69fc 100644 --- a/tests/expected/lsfd/column-name-pidfd +++ b/tests/expected/lsfd/column-name-pidfd @@ -1,2 +1,2 @@ -3 anon_inode:[pidfd] pid=1 comm= nspid=1 +3 [KNAME] pid=1 comm= nspid=1 pidfd:ASSOC,KNAME,NAME: 0 diff --git a/tests/expected/lsfd/column-type-pidfd b/tests/expected/lsfd/column-type-pidfd index 6c9a9632ea..a4379807d4 100644 --- a/tests/expected/lsfd/column-type-pidfd +++ b/tests/expected/lsfd/column-type-pidfd @@ -1,2 +1,2 @@ -3 UNKN pidfd +3 [STTYPE] pidfd pidfd:ASSOC,STTYPE,TYPE: 0 diff --git a/tests/expected/lsfd/mkfds-pidfd b/tests/expected/lsfd/mkfds-pidfd index 9484699204..bce4dd42a2 100644 --- a/tests/expected/lsfd/mkfds-pidfd +++ b/tests/expected/lsfd/mkfds-pidfd @@ -1,2 +1,2 @@ -3 UNKN anon_inodefs pid=1 comm=systemd nspid=1 systemd 1 +3 [STTYPE] [SOURCE] pid=1 comm=systemd nspid=1 systemd 1 ASSOC,STTYPE,SOURCE,NAME,PIDFD.COMM,PIDFD.PID: 0 diff --git a/tests/ts/lsfd/column-ainodeclass b/tests/ts/lsfd/column-ainodeclass index 6829494f0e..ab2abebd6a 100755 --- a/tests/ts/lsfd/column-ainodeclass +++ b/tests/ts/lsfd/column-ainodeclass @@ -42,10 +42,18 @@ for C in pidfd inotify; do fi wait "${MKFDS_PID}" } > "$TS_OUTPUT" 2>&1 + if [ "$C-$?" == "pidfd-$TS_EXIT_NOTSUPP" ]; then ts_skip_subtest "pidfd_open(2) is not available" continue fi + + STTYPE="$(head -n1 "$TS_OUTPUT" | awk '{print $2}')" + if [ "$C-$STTYPE" == "pidfd-REG" ]; then + ts_skip_subtest "pidfd is from pidfs instead of anon inode" + continue + fi + ts_finalize_subtest done diff --git a/tests/ts/lsfd/column-name b/tests/ts/lsfd/column-name index 8bf8f42178..9c67de8893 100755 --- a/tests/ts/lsfd/column-name +++ b/tests/ts/lsfd/column-name @@ -64,10 +64,17 @@ for C in ro-regular-file pidfd socketpair; do fi } > "$TS_OUTPUT" 2>&1 wait "${MKFDS_PID}" + if [ "$C-$?" == "pidfd-$TS_EXIT_NOTSUPP" ]; then ts_skip_subtest "pidfd_open(2) is not available" continue fi + + case $C in + pidfd) + sed -i -E 's/(pidfd|anon_inode):\[[a-zA-Z]+\]/[KNAME]/' "$TS_OUTPUT" + esac + ts_finalize_subtest done diff --git a/tests/ts/lsfd/column-type b/tests/ts/lsfd/column-type index 77bc5c9400..1b8aa8c6fc 100755 --- a/tests/ts/lsfd/column-type +++ b/tests/ts/lsfd/column-type @@ -50,10 +50,17 @@ for C in ro-regular-file pidfd inotify socketpair; do fi wait "${MKFDS_PID}" } > "$TS_OUTPUT" 2>&1 + if [ "$C-$?" == "pidfd-$TS_EXIT_NOTSUPP" ]; then ts_skip_subtest "pidfd_open(2) is not available" continue fi + + case $C in + pidfd) + sed -i -E 's/UNKN|REG/[STTYPE]/' "$TS_OUTPUT" + esac + ts_finalize_subtest done diff --git a/tests/ts/lsfd/mkfds-pidfd b/tests/ts/lsfd/mkfds-pidfd index c0fae4f70a..9b0ff33c60 100755 --- a/tests/ts/lsfd/mkfds-pidfd +++ b/tests/ts/lsfd/mkfds-pidfd @@ -44,8 +44,12 @@ EXPR="(PID != ${TARGET}) and (FD == 3) and (PIDFD.PID == ${TARGET})" fi wait ${MKFDS_PID} } > $TS_OUTPUT 2>&1 + if [ "$?" == "$TS_EXIT_NOTSUPP" ]; then ts_skip "pidfd_open(2) is not available" fi +sed -i -E -e 's/UNKN|REG/[STTYPE]/' -e 's/pidfs|anon_inodefs/[SOURCE]/' \ + $TS_OUTPUT + ts_finalize |