fd-001-lookup.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. // Test /proc/*/fd lookup.
  17. #undef NDEBUG
  18. #include <assert.h>
  19. #include <dirent.h>
  20. #include <errno.h>
  21. #include <limits.h>
  22. #include <sched.h>
  23. #include <stdio.h>
  24. #include <unistd.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include "proc.h"
  29. /* lstat(2) has more "coverage" in case non-symlink pops up somehow. */
  30. static void test_lookup_pass(const char *pathname)
  31. {
  32. struct stat st;
  33. ssize_t rv;
  34. memset(&st, 0, sizeof(struct stat));
  35. rv = lstat(pathname, &st);
  36. assert(rv == 0);
  37. assert(S_ISLNK(st.st_mode));
  38. }
  39. static void test_lookup_fail(const char *pathname)
  40. {
  41. struct stat st;
  42. ssize_t rv;
  43. rv = lstat(pathname, &st);
  44. assert(rv == -1 && errno == ENOENT);
  45. }
  46. static void test_lookup(unsigned int fd)
  47. {
  48. char buf[64];
  49. unsigned int c;
  50. unsigned int u;
  51. int i;
  52. snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd);
  53. test_lookup_pass(buf);
  54. /* leading junk */
  55. for (c = 1; c <= 255; c++) {
  56. if (c == '/')
  57. continue;
  58. snprintf(buf, sizeof(buf), "/proc/self/fd/%c%u", c, fd);
  59. test_lookup_fail(buf);
  60. }
  61. /* trailing junk */
  62. for (c = 1; c <= 255; c++) {
  63. if (c == '/')
  64. continue;
  65. snprintf(buf, sizeof(buf), "/proc/self/fd/%u%c", fd, c);
  66. test_lookup_fail(buf);
  67. }
  68. for (i = INT_MIN; i < INT_MIN + 1024; i++) {
  69. snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
  70. test_lookup_fail(buf);
  71. }
  72. for (i = -1024; i < 0; i++) {
  73. snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
  74. test_lookup_fail(buf);
  75. }
  76. for (u = INT_MAX - 1024; u <= (unsigned int)INT_MAX + 1024; u++) {
  77. snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
  78. test_lookup_fail(buf);
  79. }
  80. for (u = UINT_MAX - 1024; u != 0; u++) {
  81. snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
  82. test_lookup_fail(buf);
  83. }
  84. }
  85. int main(void)
  86. {
  87. struct dirent *de;
  88. unsigned int fd, target_fd;
  89. if (unshare(CLONE_FILES) == -1)
  90. return 1;
  91. /* Wipe fdtable. */
  92. do {
  93. DIR *d;
  94. d = opendir("/proc/self/fd");
  95. if (!d)
  96. return 1;
  97. de = xreaddir(d);
  98. assert(de->d_type == DT_DIR);
  99. assert(streq(de->d_name, "."));
  100. de = xreaddir(d);
  101. assert(de->d_type == DT_DIR);
  102. assert(streq(de->d_name, ".."));
  103. next:
  104. de = xreaddir(d);
  105. if (de) {
  106. unsigned long long fd_ull;
  107. unsigned int fd;
  108. char *end;
  109. assert(de->d_type == DT_LNK);
  110. fd_ull = xstrtoull(de->d_name, &end);
  111. assert(*end == '\0');
  112. assert(fd_ull == (unsigned int)fd_ull);
  113. fd = fd_ull;
  114. if (fd == dirfd(d))
  115. goto next;
  116. close(fd);
  117. }
  118. closedir(d);
  119. } while (de);
  120. /* Now fdtable is clean. */
  121. fd = open("/", O_PATH|O_DIRECTORY);
  122. assert(fd == 0);
  123. test_lookup(fd);
  124. close(fd);
  125. /* Clean again! */
  126. fd = open("/", O_PATH|O_DIRECTORY);
  127. assert(fd == 0);
  128. /* Default RLIMIT_NOFILE-1 */
  129. target_fd = 1023;
  130. while (target_fd > 0) {
  131. if (dup2(fd, target_fd) == target_fd)
  132. break;
  133. target_fd /= 2;
  134. }
  135. assert(target_fd > 0);
  136. close(fd);
  137. test_lookup(target_fd);
  138. close(target_fd);
  139. return 0;
  140. }