]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: Support pidfs
authorXi Ruoyao <xry111@xry111.site>
Wed, 3 Apr 2024 07:46:57 +0000 (15:46 +0800)
committerKarel Zak <kzak@redhat.com>
Wed, 3 Jul 2024 07:13:39 +0000 (09:13 +0200)
In Linux 6.9 pidfds are moved from the anonymous inode infrastructure to
a tiny pseudo filesystem named pidfs.  Recognize it properly.

Fixes #2865.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
(cherry picked from commit b1a48efd173c7f37d8df39a84eb25b4440335661)
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/lsfd-file.c
misc-utils/lsfd.c
misc-utils/lsfd.h

index 9b91462d6b157e8bab46c30d28f4496d091274f8..3f330146dccd933fa868ed73e577a8633cd5d06d 100644 (file)
@@ -45,6 +45,8 @@
 #include "procfs.h"
 
 #include "lsfd.h"
+#include "lsfd-pidfd.h"
+#include "pidfd-utils.h"
 
 static struct idcache *username_cache;
 
@@ -492,6 +494,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;
@@ -510,6 +528,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");
 }
 
 static void file_class_finalize(void)
@@ -783,3 +805,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;
+}
index 98820ee8422adda8f983282e0ee19572560cda7d..01e88d51b9ed675980b677dc42bef5434da5fd0e 100644 (file)
@@ -683,6 +683,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;
index e646758ca2a9d7f68a8a600a1e1158f1cc460844..f0f17d5b043af07a8435e9fadd4fd61556737d6e 100644 (file)
@@ -228,7 +228,7 @@ struct file_class {
 };
 
 extern const struct file_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
@@ -307,4 +307,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 */