]> Git Repo - linux.git/blob - samples/vfs/test-list-all-mounts.c
Linux 6.14-rc3
[linux.git] / samples / vfs / test-list-all-mounts.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 // Copyright (c) 2024 Christian Brauner <[email protected]>
3
4 #define _GNU_SOURCE
5 #include <errno.h>
6 #include <limits.h>
7 #include <linux/types.h>
8 #include <inttypes.h>
9 #include <stdio.h>
10
11 #include "../../tools/testing/selftests/pidfd/pidfd.h"
12 #include "samples-vfs.h"
13
14 static int __statmount(__u64 mnt_id, __u64 mnt_ns_id, __u64 mask,
15                        struct statmount *stmnt, size_t bufsize,
16                        unsigned int flags)
17 {
18         struct mnt_id_req req = {
19                 .size           = MNT_ID_REQ_SIZE_VER1,
20                 .mnt_id         = mnt_id,
21                 .param          = mask,
22                 .mnt_ns_id      = mnt_ns_id,
23         };
24
25         return syscall(__NR_statmount, &req, stmnt, bufsize, flags);
26 }
27
28 static struct statmount *sys_statmount(__u64 mnt_id, __u64 mnt_ns_id,
29                                        __u64 mask, unsigned int flags)
30 {
31         size_t bufsize = 1 << 15;
32         struct statmount *stmnt = NULL, *tmp = NULL;
33         int ret;
34
35         for (;;) {
36                 tmp = realloc(stmnt, bufsize);
37                 if (!tmp)
38                         goto out;
39
40                 stmnt = tmp;
41                 ret = __statmount(mnt_id, mnt_ns_id, mask, stmnt, bufsize, flags);
42                 if (!ret)
43                         return stmnt;
44
45                 if (errno != EOVERFLOW)
46                         goto out;
47
48                 bufsize <<= 1;
49                 if (bufsize >= UINT_MAX / 2)
50                         goto out;
51         }
52
53 out:
54         free(stmnt);
55         return NULL;
56 }
57
58 static ssize_t sys_listmount(__u64 mnt_id, __u64 last_mnt_id, __u64 mnt_ns_id,
59                              __u64 list[], size_t num, unsigned int flags)
60 {
61         struct mnt_id_req req = {
62                 .size           = MNT_ID_REQ_SIZE_VER1,
63                 .mnt_id         = mnt_id,
64                 .param          = last_mnt_id,
65                 .mnt_ns_id      = mnt_ns_id,
66         };
67
68         return syscall(__NR_listmount, &req, list, num, flags);
69 }
70
71 int main(int argc, char *argv[])
72 {
73 #define LISTMNT_BUFFER 10
74         __u64 list[LISTMNT_BUFFER], last_mnt_id = 0;
75         int ret, pidfd, fd_mntns;
76         struct mnt_ns_info info = {};
77
78         pidfd = sys_pidfd_open(getpid(), 0);
79         if (pidfd < 0)
80                 die_errno("pidfd_open failed");
81
82         fd_mntns = ioctl(pidfd, PIDFD_GET_MNT_NAMESPACE, 0);
83         if (fd_mntns < 0)
84                 die_errno("ioctl(PIDFD_GET_MNT_NAMESPACE) failed");
85
86         ret = ioctl(fd_mntns, NS_MNT_GET_INFO, &info);
87         if (ret < 0)
88                 die_errno("ioctl(NS_GET_MNTNS_ID) failed");
89
90         printf("Listing %u mounts for mount namespace %" PRIu64 "\n",
91                info.nr_mounts, (uint64_t)info.mnt_ns_id);
92         for (;;) {
93                 ssize_t nr_mounts;
94 next:
95                 nr_mounts = sys_listmount(LSMT_ROOT, last_mnt_id,
96                                           info.mnt_ns_id, list, LISTMNT_BUFFER,
97                                           0);
98                 if (nr_mounts <= 0) {
99                         int fd_mntns_next;
100
101                         printf("Finished listing %u mounts for mount namespace %" PRIu64 "\n\n",
102                                info.nr_mounts, (uint64_t)info.mnt_ns_id);
103                         fd_mntns_next = ioctl(fd_mntns, NS_MNT_GET_NEXT, &info);
104                         if (fd_mntns_next < 0) {
105                                 if (errno == ENOENT) {
106                                         printf("Finished listing all mount namespaces\n");
107                                         exit(0);
108                                 }
109                                 die_errno("ioctl(NS_MNT_GET_NEXT) failed");
110                         }
111                         close(fd_mntns);
112                         fd_mntns = fd_mntns_next;
113                         last_mnt_id = 0;
114                         printf("Listing %u mounts for mount namespace %" PRIu64 "\n",
115                                info.nr_mounts, (uint64_t)info.mnt_ns_id);
116                         goto next;
117                 }
118
119                 for (size_t cur = 0; cur < nr_mounts; cur++) {
120                         struct statmount *stmnt;
121
122                         last_mnt_id = list[cur];
123
124                         stmnt = sys_statmount(last_mnt_id, info.mnt_ns_id,
125                                               STATMOUNT_SB_BASIC |
126                                               STATMOUNT_MNT_BASIC |
127                                               STATMOUNT_MNT_ROOT |
128                                               STATMOUNT_MNT_POINT |
129                                               STATMOUNT_MNT_NS_ID |
130                                               STATMOUNT_MNT_OPTS |
131                                               STATMOUNT_FS_TYPE, 0);
132                         if (!stmnt) {
133                                 printf("Failed to statmount(%" PRIu64 ") in mount namespace(%" PRIu64 ")\n",
134                                        (uint64_t)last_mnt_id, (uint64_t)info.mnt_ns_id);
135                                 continue;
136                         }
137
138                         printf("mnt_id:\t\t%" PRIu64 "\nmnt_parent_id:\t%" PRIu64 "\nfs_type:\t%s\nmnt_root:\t%s\nmnt_point:\t%s\nmnt_opts:\t%s\n\n",
139                                (uint64_t)stmnt->mnt_id,
140                                (uint64_t)stmnt->mnt_parent_id,
141                                stmnt->str + stmnt->fs_type,
142                                stmnt->str + stmnt->mnt_root,
143                                stmnt->str + stmnt->mnt_point,
144                                stmnt->str + stmnt->mnt_opts);
145                         free(stmnt);
146                 }
147         }
148
149         exit(0);
150 }
This page took 0.035051 seconds and 4 git commands to generate.