aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2024-04-08 09:48:10 +0200
committerKarel Zak <kzak@redhat.com>2024-04-08 09:48:10 +0200
commit44b92ef3bb950f5680c5febcca5d4b47e67c628c (patch)
treeb6137d6b7fb6f37cda0338ebb985543f5260a96d
parentdf72ff49ed5dabb388c4a7c914c272ffd4264471 (diff)
parent04db2ba9008e9635286b1aafc8ecd9533a0a91bf (diff)
downloadutil-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.h1
-rw-r--r--misc-utils/Makemodule.am4
-rw-r--r--misc-utils/lsfd-file.c96
-rw-r--r--misc-utils/lsfd-pidfd.c95
-rw-r--r--misc-utils/lsfd-pidfd.h37
-rw-r--r--misc-utils/lsfd-unkn.c71
-rw-r--r--misc-utils/lsfd.c3
-rw-r--r--misc-utils/lsfd.h7
-rw-r--r--misc-utils/meson.build1
-rw-r--r--tests/expected/lsfd/column-name-pidfd2
-rw-r--r--tests/expected/lsfd/column-type-pidfd2
-rw-r--r--tests/expected/lsfd/mkfds-pidfd2
-rwxr-xr-xtests/ts/lsfd/column-ainodeclass8
-rwxr-xr-xtests/ts/lsfd/column-name7
-rwxr-xr-xtests/ts/lsfd/column-type7
-rwxr-xr-xtests/ts/lsfd/mkfds-pidfd4
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