test-list-all-mounts.c 4.5 KB

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