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