]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: add a function to get the name of filesystem from a given minor number
authorMasatake YAMATO <yamato@redhat.com>
Sun, 9 May 2021 01:41:34 +0000 (10:41 +0900)
committerKarel Zak <kzak@redhat.com>
Wed, 6 Oct 2021 09:01:53 +0000 (11:01 +0200)
Signed-off-by: Masatake YAMATO <yamato@redhat.com>
misc-utils/lsfd.c
misc-utils/lsfd.h

index 8204ca486b8eab82351b80bb1dd6fe754b00e61e..65aff806c48bfeeb02f9c6f29bef5b282a838fbd 100644 (file)
@@ -74,6 +74,15 @@ struct map {
        unsigned int read:1, write:1, exec:1, shared:1;
 };
 
+/*
+ * /proc/$pid/mountinfo entries
+ */
+struct nodev {
+       struct list_head nodevs;
+       unsigned long minor;
+       char *filesystem;
+};
+
 /*
  * Column related stuffs
  */
@@ -230,11 +239,34 @@ static void free_file(struct file *file)
        free(file);
 }
 
+static struct nodev* make_nodev(unsigned long minor, const char *filesystem)
+{
+       struct nodev *nodev = xcalloc(1, sizeof(*nodev));
+
+       INIT_LIST_HEAD(&nodev->nodevs);
+       nodev->minor = minor;
+       nodev->filesystem = xstrdup(filesystem);
+
+       return nodev;
+}
+
+static void free_nodev(struct nodev *nodev)
+{
+       free(nodev->filesystem);
+       free(nodev);
+}
+
+static void free_nodevs(struct list_head *nodevs)
+{
+       list_free(nodevs, struct nodev, nodevs, free_nodev);
+}
+
 static void free_proc(struct proc *proc)
 {
        list_free(&proc->files, struct file, files, free_file);
 
        free(proc->command);
+       free_nodevs(&proc->nodevs);
        free(proc);
 }
 
@@ -715,9 +747,43 @@ static void collect_namespace_files(struct proc *proc)
                               ARRAY_SIZE(namespace_assocs));
 }
 
+static FILE *open_mountinfo(pid_t pid, pid_t tid)
+{
+       return fopenf("r", "/proc/%d/task/%d/mountinfo", pid, tid);
+}
+
+static void read_nodevs(struct list_head *nodevs_list, FILE *mountinfo_fp)
+{
+       /* This can be very long.
+          A line in mountinfo can have more than 3 paths. */
+       char line[PATH_MAX * 3 + 256];
+       while (fgets(line, sizeof(line), mountinfo_fp)) {
+               struct nodev *nodev;
+               unsigned long major, minor;
+               char filesystem[256];
+
+               /* 23 61 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:2 - sysfs sysfs rw,seclabel */
+               if(sscanf(line, "%*d %*d %lu:%lu %*s %*s %*s %*[^-] - %s %*[^\n]",
+                         &major, &minor, filesystem) != 3)
+                       /* 1600 1458 0:55 / / rw,nodev,relatime - overlay overlay rw,context="s... */
+                       if (sscanf(line, "%*d %*d %lu:%lu %*s %*s %*s - %s %*[^\n]",
+                                  &major, &minor, filesystem) != 3)
+                               continue;
+
+               if (major != 0)
+                       continue;
+
+               nodev = make_nodev(minor, filesystem);
+               list_add_tail(&nodev->nodevs, nodevs_list);
+       }
+}
+
 static void fill_proc(struct proc *proc)
 {
+       FILE *mountinfo_fp;
+
        INIT_LIST_HEAD(&proc->files);
+       INIT_LIST_HEAD(&proc->nodevs);
 
        proc->command = proc_get_command_name(proc->pid);
        if (!proc->command)
@@ -733,6 +799,13 @@ static void fill_proc(struct proc *proc)
 
        collect_namespace_files(proc);
 
+       mountinfo_fp = open_mountinfo(proc->leader->pid,
+                                     proc->pid);
+       if (mountinfo_fp) {
+               read_nodevs(&proc->nodevs, mountinfo_fp);
+               fclose(mountinfo_fp);
+       }
+
        /* If kcmp is not available,
         * there is no way to no whether threads share resources.
         * In such cases, we must pay the costs: call collect_mem_files()
@@ -1080,6 +1153,17 @@ unsigned long add_name(struct name_manager *nm, const char *name)
        return e->id;
 }
 
+const char *get_nodev_filesystem(struct proc *proc, unsigned long minor)
+{
+       struct list_head *n;
+       list_for_each (n, &proc->nodevs) {
+               struct nodev *nodev = list_entry(n, struct nodev, nodevs);
+               if (nodev->minor == minor)
+                       return nodev->filesystem;
+       }
+       return NULL;
+}
+
 DIR *opendirf(const char *format, ...)
 {
        va_list ap;
index 6f4e5d840d4d7f5a0bbc4f4a89c735e3c03c32b0..a274ad9c70d38a4f8f958e7f633df23f8d1fac3d 100644 (file)
@@ -106,6 +106,7 @@ struct proc {
        uid_t uid;
        struct list_head procs;
        struct list_head files;
+       struct list_head nodevs;
 };
 
 /*
@@ -166,5 +167,6 @@ unsigned long add_name(struct name_manager *nm, const char *name);
 const char *get_partition(dev_t dev);
 const char *get_chrdrv(unsigned long major);
 const char *get_miscdev(unsigned long minor);
+const char *get_nodev_filesystem(struct proc *proc, unsigned long minor);
 
 #endif /* UTIL_LINUX_LSFD_H */