File Index
Files and directories
Sign in
FILE

test-list-all-mounts.c

File preview with syntax highlighting.

linux-6.19.14/samples/vfs/test-list-all-mounts.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2// Copyright (c) 2024 Christian Brauner <brauner@kernel.org>
  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
 14static 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
 28static 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
 53out:
 54	free(stmnt);
 55	return NULL;
 56}
 57
 58static 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
 71int 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;
 94next:
 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}
~/ Read-only file preview.