162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci// Test 1762306a36Sopenharmony_ci// 1) read and lseek on every file in /proc 1862306a36Sopenharmony_ci// 2) readlink of every symlink in /proc 1962306a36Sopenharmony_ci// 3) recursively (1) + (2) for every directory in /proc 2062306a36Sopenharmony_ci// 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs 2162306a36Sopenharmony_ci// 5) write to /proc/sysrq-trigger 2262306a36Sopenharmony_ci#undef NDEBUG 2362306a36Sopenharmony_ci#include <assert.h> 2462306a36Sopenharmony_ci#include <errno.h> 2562306a36Sopenharmony_ci#include <sys/types.h> 2662306a36Sopenharmony_ci#include <dirent.h> 2762306a36Sopenharmony_ci#include <stdbool.h> 2862306a36Sopenharmony_ci#include <stdlib.h> 2962306a36Sopenharmony_ci#include <stdio.h> 3062306a36Sopenharmony_ci#include <string.h> 3162306a36Sopenharmony_ci#include <sys/stat.h> 3262306a36Sopenharmony_ci#include <sys/vfs.h> 3362306a36Sopenharmony_ci#include <fcntl.h> 3462306a36Sopenharmony_ci#include <unistd.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "proc.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void f_reg(DIR *d, const char *filename) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci char buf[4096]; 4162306a36Sopenharmony_ci int fd; 4262306a36Sopenharmony_ci ssize_t rv; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* read from /proc/kmsg can block */ 4562306a36Sopenharmony_ci fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK); 4662306a36Sopenharmony_ci if (fd == -1) 4762306a36Sopenharmony_ci return; 4862306a36Sopenharmony_ci /* struct proc_ops::proc_lseek is mandatory if file is seekable. */ 4962306a36Sopenharmony_ci (void)lseek(fd, 0, SEEK_SET); 5062306a36Sopenharmony_ci rv = read(fd, buf, sizeof(buf)); 5162306a36Sopenharmony_ci assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); 5262306a36Sopenharmony_ci close(fd); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci int fd; 5862306a36Sopenharmony_ci ssize_t rv; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci fd = openat(dirfd(d), filename, O_WRONLY); 6162306a36Sopenharmony_ci if (fd == -1) 6262306a36Sopenharmony_ci return; 6362306a36Sopenharmony_ci rv = write(fd, buf, len); 6462306a36Sopenharmony_ci assert((0 <= rv && rv <= len) || rv == -1); 6562306a36Sopenharmony_ci close(fd); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void f_lnk(DIR *d, const char *filename) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci char buf[4096]; 7162306a36Sopenharmony_ci ssize_t rv; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci rv = readlinkat(dirfd(d), filename, buf, sizeof(buf)); 7462306a36Sopenharmony_ci assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void f(DIR *d, unsigned int level) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct dirent *de; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci de = xreaddir(d); 8262306a36Sopenharmony_ci assert(de->d_type == DT_DIR); 8362306a36Sopenharmony_ci assert(streq(de->d_name, ".")); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci de = xreaddir(d); 8662306a36Sopenharmony_ci assert(de->d_type == DT_DIR); 8762306a36Sopenharmony_ci assert(streq(de->d_name, "..")); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci while ((de = xreaddir(d))) { 9062306a36Sopenharmony_ci assert(!streq(de->d_name, ".")); 9162306a36Sopenharmony_ci assert(!streq(de->d_name, "..")); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci switch (de->d_type) { 9462306a36Sopenharmony_ci DIR *dd; 9562306a36Sopenharmony_ci int fd; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci case DT_REG: 9862306a36Sopenharmony_ci if (level == 0 && streq(de->d_name, "sysrq-trigger")) { 9962306a36Sopenharmony_ci f_reg_write(d, de->d_name, "h", 1); 10062306a36Sopenharmony_ci } else if (level == 1 && streq(de->d_name, "clear_refs")) { 10162306a36Sopenharmony_ci f_reg_write(d, de->d_name, "1", 1); 10262306a36Sopenharmony_ci } else if (level == 3 && streq(de->d_name, "clear_refs")) { 10362306a36Sopenharmony_ci f_reg_write(d, de->d_name, "1", 1); 10462306a36Sopenharmony_ci } else { 10562306a36Sopenharmony_ci f_reg(d, de->d_name); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci case DT_DIR: 10962306a36Sopenharmony_ci fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY); 11062306a36Sopenharmony_ci if (fd == -1) 11162306a36Sopenharmony_ci continue; 11262306a36Sopenharmony_ci dd = fdopendir(fd); 11362306a36Sopenharmony_ci if (!dd) 11462306a36Sopenharmony_ci continue; 11562306a36Sopenharmony_ci f(dd, level + 1); 11662306a36Sopenharmony_ci closedir(dd); 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci case DT_LNK: 11962306a36Sopenharmony_ci f_lnk(d, de->d_name); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci default: 12262306a36Sopenharmony_ci assert(0); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ciint main(void) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci DIR *d; 13062306a36Sopenharmony_ci struct statfs sfs; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci d = opendir("/proc"); 13362306a36Sopenharmony_ci if (!d) 13462306a36Sopenharmony_ci return 4; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Ensure /proc is proc. */ 13762306a36Sopenharmony_ci if (fstatfs(dirfd(d), &sfs) == -1) { 13862306a36Sopenharmony_ci return 1; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci if (sfs.f_type != 0x9fa0) { 14162306a36Sopenharmony_ci fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type); 14262306a36Sopenharmony_ci return 2; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci f(d, 0); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 149