Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/samples/vfs/test-list-all-mounts.c
26278 views
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 |
132
STATMOUNT_MNT_UIDMAP |
133
STATMOUNT_MNT_GIDMAP, 0);
134
if (!stmnt) {
135
printf("Failed to statmount(%" PRIu64 ") in mount namespace(%" PRIu64 ")\n",
136
(uint64_t)last_mnt_id, (uint64_t)info.mnt_ns_id);
137
continue;
138
}
139
140
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",
141
(uint64_t)stmnt->mnt_id,
142
(uint64_t)stmnt->mnt_parent_id,
143
(stmnt->mask & STATMOUNT_FS_TYPE) ? stmnt->str + stmnt->fs_type : "",
144
(stmnt->mask & STATMOUNT_MNT_ROOT) ? stmnt->str + stmnt->mnt_root : "",
145
(stmnt->mask & STATMOUNT_MNT_POINT) ? stmnt->str + stmnt->mnt_point : "",
146
(stmnt->mask & STATMOUNT_MNT_OPTS) ? stmnt->str + stmnt->mnt_opts : "");
147
148
if (stmnt->mask & STATMOUNT_MNT_UIDMAP) {
149
const char *idmap = stmnt->str + stmnt->mnt_uidmap;
150
151
for (size_t idx = 0; idx < stmnt->mnt_uidmap_num; idx++) {
152
printf("mnt_uidmap[%zu]:\t%s\n", idx, idmap);
153
idmap += strlen(idmap) + 1;
154
}
155
}
156
157
if (stmnt->mask & STATMOUNT_MNT_GIDMAP) {
158
const char *idmap = stmnt->str + stmnt->mnt_gidmap;
159
160
for (size_t idx = 0; idx < stmnt->mnt_gidmap_num; idx++) {
161
printf("mnt_gidmap[%zu]:\t%s\n", idx, idmap);
162
idmap += strlen(idmap) + 1;
163
}
164
}
165
166
printf("\n");
167
168
free(stmnt);
169
}
170
}
171
172
exit(0);
173
}
174
175