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 of 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 36 #include "proc.h" 37 38 static void f_reg(DIR *d, const char *filename) 39 { 40 char buf[4096]; 41 int fd; 42 ssize_t rv; 43 44 /* read from /proc/kmsg can block */ 45 fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK); 46 if (fd == -1) 47 return; 48 rv = read(fd, buf, sizeof(buf)); 49 assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); 50 close(fd); 51 } 52 53 static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len) 54 { 55 int fd; 56 ssize_t rv; 57 58 fd = openat(dirfd(d), filename, O_WRONLY); 59 if (fd == -1) 60 return; 61 rv = write(fd, buf, len); 62 assert((0 <= rv && rv <= len) || rv == -1); 63 close(fd); 64 } 65 66 static void f_lnk(DIR *d, const char *filename) 67 { 68 char buf[4096]; 69 ssize_t rv; 70 71 rv = readlinkat(dirfd(d), filename, buf, sizeof(buf)); 72 assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); 73 } 74 75 static void f(DIR *d, unsigned int level) 76 { 77 struct dirent *de; 78 79 de = xreaddir(d); 80 assert(de->d_type == DT_DIR); 81 assert(streq(de->d_name, ".")); 82 83 de = xreaddir(d); 84 assert(de->d_type == DT_DIR); 85 assert(streq(de->d_name, "..")); 86 87 while ((de = xreaddir(d))) { 88 assert(!streq(de->d_name, ".")); 89 assert(!streq(de->d_name, "..")); 90 91 switch (de->d_type) { 92 DIR *dd; 93 int fd; 94 95 case DT_REG: 96 if (level == 0 && streq(de->d_name, "sysrq-trigger")) { 97 f_reg_write(d, de->d_name, "h", 1); 98 } else if (level == 1 && streq(de->d_name, "clear_refs")) { 99 f_reg_write(d, de->d_name, "1", 1); 100 } else if (level == 3 && streq(de->d_name, "clear_refs")) { 101 f_reg_write(d, de->d_name, "1", 1); 102 } else { 103 f_reg(d, de->d_name); 104 } 105 break; 106 case DT_DIR: 107 fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY); 108 if (fd == -1) 109 continue; 110 dd = fdopendir(fd); 111 if (!dd) 112 continue; 113 f(dd, level + 1); 114 closedir(dd); 115 break; 116 case DT_LNK: 117 f_lnk(d, de->d_name); 118 break; 119 default: 120 assert(0); 121 } 122 } 123 } 124 125 int main(void) 126 { 127 DIR *d; 128 struct statfs sfs; 129 130 d = opendir("/proc"); 131 if (!d) 132 return 4; 133 134 /* Ensure /proc is proc. */ 135 if (fstatfs(dirfd(d), &sfs) == -1) { 136 return 1; 137 } 138 if (sfs.f_type != 0x9fa0) { 139 fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type); 140 return 2; 141 } 142 143 f(d, 0); 144 145 return 0; 146 } 147