1*053f45beSAndroid Build Coastguard Worker /*
2*053f45beSAndroid Build Coastguard Worker * Copyright © 2018 Alexey Dobriyan <[email protected]>
3*053f45beSAndroid Build Coastguard Worker *
4*053f45beSAndroid Build Coastguard Worker * Permission to use, copy, modify, and distribute this software for any
5*053f45beSAndroid Build Coastguard Worker * purpose with or without fee is hereby granted, provided that the above
6*053f45beSAndroid Build Coastguard Worker * copyright notice and this permission notice appear in all copies.
7*053f45beSAndroid Build Coastguard Worker *
8*053f45beSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*053f45beSAndroid Build Coastguard Worker * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*053f45beSAndroid Build Coastguard Worker * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*053f45beSAndroid Build Coastguard Worker * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*053f45beSAndroid Build Coastguard Worker * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*053f45beSAndroid Build Coastguard Worker * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*053f45beSAndroid Build Coastguard Worker * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*053f45beSAndroid Build Coastguard Worker */
16*053f45beSAndroid Build Coastguard Worker // Test
17*053f45beSAndroid Build Coastguard Worker // 1) read and lseek on every file in /proc
18*053f45beSAndroid Build Coastguard Worker // 2) readlink of every symlink in /proc
19*053f45beSAndroid Build Coastguard Worker // 3) recursively (1) + (2) for every directory in /proc
20*053f45beSAndroid Build Coastguard Worker // 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs
21*053f45beSAndroid Build Coastguard Worker // 5) write to /proc/sysrq-trigger
22*053f45beSAndroid Build Coastguard Worker #undef NDEBUG
23*053f45beSAndroid Build Coastguard Worker #include <assert.h>
24*053f45beSAndroid Build Coastguard Worker #include <errno.h>
25*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
26*053f45beSAndroid Build Coastguard Worker #include <dirent.h>
27*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
28*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
29*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
30*053f45beSAndroid Build Coastguard Worker #include <string.h>
31*053f45beSAndroid Build Coastguard Worker #include <sys/stat.h>
32*053f45beSAndroid Build Coastguard Worker #include <sys/vfs.h>
33*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
34*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
35*053f45beSAndroid Build Coastguard Worker
36*053f45beSAndroid Build Coastguard Worker #include "proc.h"
37*053f45beSAndroid Build Coastguard Worker
f_reg(DIR * d,const char * filename)38*053f45beSAndroid Build Coastguard Worker static void f_reg(DIR *d, const char *filename)
39*053f45beSAndroid Build Coastguard Worker {
40*053f45beSAndroid Build Coastguard Worker char buf[4096];
41*053f45beSAndroid Build Coastguard Worker int fd;
42*053f45beSAndroid Build Coastguard Worker ssize_t rv;
43*053f45beSAndroid Build Coastguard Worker
44*053f45beSAndroid Build Coastguard Worker /* read from /proc/kmsg can block */
45*053f45beSAndroid Build Coastguard Worker fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK);
46*053f45beSAndroid Build Coastguard Worker if (fd == -1)
47*053f45beSAndroid Build Coastguard Worker return;
48*053f45beSAndroid Build Coastguard Worker /* struct proc_ops::proc_lseek is mandatory if file is seekable. */
49*053f45beSAndroid Build Coastguard Worker (void)lseek(fd, 0, SEEK_SET);
50*053f45beSAndroid Build Coastguard Worker rv = read(fd, buf, sizeof(buf));
51*053f45beSAndroid Build Coastguard Worker assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);
52*053f45beSAndroid Build Coastguard Worker close(fd);
53*053f45beSAndroid Build Coastguard Worker }
54*053f45beSAndroid Build Coastguard Worker
f_reg_write(DIR * d,const char * filename,const char * buf,size_t len)55*053f45beSAndroid Build Coastguard Worker static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len)
56*053f45beSAndroid Build Coastguard Worker {
57*053f45beSAndroid Build Coastguard Worker int fd;
58*053f45beSAndroid Build Coastguard Worker ssize_t rv;
59*053f45beSAndroid Build Coastguard Worker
60*053f45beSAndroid Build Coastguard Worker fd = openat(dirfd(d), filename, O_WRONLY);
61*053f45beSAndroid Build Coastguard Worker if (fd == -1)
62*053f45beSAndroid Build Coastguard Worker return;
63*053f45beSAndroid Build Coastguard Worker rv = write(fd, buf, len);
64*053f45beSAndroid Build Coastguard Worker assert((0 <= rv && rv <= len) || rv == -1);
65*053f45beSAndroid Build Coastguard Worker close(fd);
66*053f45beSAndroid Build Coastguard Worker }
67*053f45beSAndroid Build Coastguard Worker
f_lnk(DIR * d,const char * filename)68*053f45beSAndroid Build Coastguard Worker static void f_lnk(DIR *d, const char *filename)
69*053f45beSAndroid Build Coastguard Worker {
70*053f45beSAndroid Build Coastguard Worker char buf[4096];
71*053f45beSAndroid Build Coastguard Worker ssize_t rv;
72*053f45beSAndroid Build Coastguard Worker
73*053f45beSAndroid Build Coastguard Worker rv = readlinkat(dirfd(d), filename, buf, sizeof(buf));
74*053f45beSAndroid Build Coastguard Worker assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);
75*053f45beSAndroid Build Coastguard Worker }
76*053f45beSAndroid Build Coastguard Worker
f(DIR * d,unsigned int level)77*053f45beSAndroid Build Coastguard Worker static void f(DIR *d, unsigned int level)
78*053f45beSAndroid Build Coastguard Worker {
79*053f45beSAndroid Build Coastguard Worker struct dirent *de;
80*053f45beSAndroid Build Coastguard Worker
81*053f45beSAndroid Build Coastguard Worker de = xreaddir(d);
82*053f45beSAndroid Build Coastguard Worker assert(de->d_type == DT_DIR);
83*053f45beSAndroid Build Coastguard Worker assert(streq(de->d_name, "."));
84*053f45beSAndroid Build Coastguard Worker
85*053f45beSAndroid Build Coastguard Worker de = xreaddir(d);
86*053f45beSAndroid Build Coastguard Worker assert(de->d_type == DT_DIR);
87*053f45beSAndroid Build Coastguard Worker assert(streq(de->d_name, ".."));
88*053f45beSAndroid Build Coastguard Worker
89*053f45beSAndroid Build Coastguard Worker while ((de = xreaddir(d))) {
90*053f45beSAndroid Build Coastguard Worker assert(!streq(de->d_name, "."));
91*053f45beSAndroid Build Coastguard Worker assert(!streq(de->d_name, ".."));
92*053f45beSAndroid Build Coastguard Worker
93*053f45beSAndroid Build Coastguard Worker switch (de->d_type) {
94*053f45beSAndroid Build Coastguard Worker DIR *dd;
95*053f45beSAndroid Build Coastguard Worker int fd;
96*053f45beSAndroid Build Coastguard Worker
97*053f45beSAndroid Build Coastguard Worker case DT_REG:
98*053f45beSAndroid Build Coastguard Worker if (level == 0 && streq(de->d_name, "sysrq-trigger")) {
99*053f45beSAndroid Build Coastguard Worker f_reg_write(d, de->d_name, "h", 1);
100*053f45beSAndroid Build Coastguard Worker } else if (level == 1 && streq(de->d_name, "clear_refs")) {
101*053f45beSAndroid Build Coastguard Worker f_reg_write(d, de->d_name, "1", 1);
102*053f45beSAndroid Build Coastguard Worker } else if (level == 3 && streq(de->d_name, "clear_refs")) {
103*053f45beSAndroid Build Coastguard Worker f_reg_write(d, de->d_name, "1", 1);
104*053f45beSAndroid Build Coastguard Worker } else {
105*053f45beSAndroid Build Coastguard Worker f_reg(d, de->d_name);
106*053f45beSAndroid Build Coastguard Worker }
107*053f45beSAndroid Build Coastguard Worker break;
108*053f45beSAndroid Build Coastguard Worker case DT_DIR:
109*053f45beSAndroid Build Coastguard Worker fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY);
110*053f45beSAndroid Build Coastguard Worker if (fd == -1)
111*053f45beSAndroid Build Coastguard Worker continue;
112*053f45beSAndroid Build Coastguard Worker dd = fdopendir(fd);
113*053f45beSAndroid Build Coastguard Worker if (!dd)
114*053f45beSAndroid Build Coastguard Worker continue;
115*053f45beSAndroid Build Coastguard Worker f(dd, level + 1);
116*053f45beSAndroid Build Coastguard Worker closedir(dd);
117*053f45beSAndroid Build Coastguard Worker break;
118*053f45beSAndroid Build Coastguard Worker case DT_LNK:
119*053f45beSAndroid Build Coastguard Worker f_lnk(d, de->d_name);
120*053f45beSAndroid Build Coastguard Worker break;
121*053f45beSAndroid Build Coastguard Worker default:
122*053f45beSAndroid Build Coastguard Worker assert(0);
123*053f45beSAndroid Build Coastguard Worker }
124*053f45beSAndroid Build Coastguard Worker }
125*053f45beSAndroid Build Coastguard Worker }
126*053f45beSAndroid Build Coastguard Worker
main(void)127*053f45beSAndroid Build Coastguard Worker int main(void)
128*053f45beSAndroid Build Coastguard Worker {
129*053f45beSAndroid Build Coastguard Worker DIR *d;
130*053f45beSAndroid Build Coastguard Worker struct statfs sfs;
131*053f45beSAndroid Build Coastguard Worker
132*053f45beSAndroid Build Coastguard Worker d = opendir("/proc");
133*053f45beSAndroid Build Coastguard Worker if (!d)
134*053f45beSAndroid Build Coastguard Worker return 4;
135*053f45beSAndroid Build Coastguard Worker
136*053f45beSAndroid Build Coastguard Worker /* Ensure /proc is proc. */
137*053f45beSAndroid Build Coastguard Worker if (fstatfs(dirfd(d), &sfs) == -1) {
138*053f45beSAndroid Build Coastguard Worker return 1;
139*053f45beSAndroid Build Coastguard Worker }
140*053f45beSAndroid Build Coastguard Worker if (sfs.f_type != 0x9fa0) {
141*053f45beSAndroid Build Coastguard Worker fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type);
142*053f45beSAndroid Build Coastguard Worker return 2;
143*053f45beSAndroid Build Coastguard Worker }
144*053f45beSAndroid Build Coastguard Worker
145*053f45beSAndroid Build Coastguard Worker f(d, 0);
146*053f45beSAndroid Build Coastguard Worker
147*053f45beSAndroid Build Coastguard Worker return 0;
148*053f45beSAndroid Build Coastguard Worker }
149