read.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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
  17. // 1) read and lseek on every file in /proc
  18. // 2) readlink of every symlink in /proc
  19. // 3) recursively (1) + (2) for every directory in /proc
  20. // 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs
  21. // 5) write to /proc/sysrq-trigger
  22. #undef NDEBUG
  23. #include <assert.h>
  24. #include <errno.h>
  25. #include <sys/types.h>
  26. #include <dirent.h>
  27. #include <stdbool.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <sys/stat.h>
  32. #include <sys/vfs.h>
  33. #include <fcntl.h>
  34. #include <unistd.h>
  35. #include "proc.h"
  36. static void f_reg(DIR *d, const char *filename)
  37. {
  38. char buf[4096];
  39. int fd;
  40. ssize_t rv;
  41. /* read from /proc/kmsg can block */
  42. fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK);
  43. if (fd == -1)
  44. return;
  45. /* struct proc_ops::proc_lseek is mandatory if file is seekable. */
  46. (void)lseek(fd, 0, SEEK_SET);
  47. rv = read(fd, buf, sizeof(buf));
  48. assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);
  49. close(fd);
  50. }
  51. static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len)
  52. {
  53. int fd;
  54. ssize_t rv;
  55. fd = openat(dirfd(d), filename, O_WRONLY);
  56. if (fd == -1)
  57. return;
  58. rv = write(fd, buf, len);
  59. assert((0 <= rv && rv <= len) || rv == -1);
  60. close(fd);
  61. }
  62. static void f_lnk(DIR *d, const char *filename)
  63. {
  64. char buf[4096];
  65. ssize_t rv;
  66. rv = readlinkat(dirfd(d), filename, buf, sizeof(buf));
  67. assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);
  68. }
  69. static void f(DIR *d, unsigned int level)
  70. {
  71. struct dirent *de;
  72. de = xreaddir(d);
  73. assert(de->d_type == DT_DIR);
  74. assert(streq(de->d_name, "."));
  75. de = xreaddir(d);
  76. assert(de->d_type == DT_DIR);
  77. assert(streq(de->d_name, ".."));
  78. while ((de = xreaddir(d))) {
  79. assert(!streq(de->d_name, "."));
  80. assert(!streq(de->d_name, ".."));
  81. switch (de->d_type) {
  82. DIR *dd;
  83. int fd;
  84. case DT_REG:
  85. if (level == 0 && streq(de->d_name, "sysrq-trigger")) {
  86. f_reg_write(d, de->d_name, "h", 1);
  87. } else if (level == 1 && streq(de->d_name, "clear_refs")) {
  88. f_reg_write(d, de->d_name, "1", 1);
  89. } else if (level == 3 && streq(de->d_name, "clear_refs")) {
  90. f_reg_write(d, de->d_name, "1", 1);
  91. } else {
  92. f_reg(d, de->d_name);
  93. }
  94. break;
  95. case DT_DIR:
  96. fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY);
  97. if (fd == -1)
  98. continue;
  99. dd = fdopendir(fd);
  100. if (!dd)
  101. continue;
  102. f(dd, level + 1);
  103. closedir(dd);
  104. break;
  105. case DT_LNK:
  106. f_lnk(d, de->d_name);
  107. break;
  108. default:
  109. assert(0);
  110. }
  111. }
  112. }
  113. int main(void)
  114. {
  115. DIR *d;
  116. struct statfs sfs;
  117. d = opendir("/proc");
  118. if (!d)
  119. return 4;
  120. /* Ensure /proc is proc. */
  121. if (fstatfs(dirfd(d), &sfs) == -1) {
  122. return 1;
  123. }
  124. if (sfs.f_type != 0x9fa0) {
  125. fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type);
  126. return 2;
  127. }
  128. f(d, 0);
  129. return 0;
  130. }