14Srgrimes/* 24Srgrimes * Copyright �� 2018 Alexey Dobriyan <adobriyan@gmail.com> 34Srgrimes * 44Srgrimes * Permission to use, copy, modify, and distribute this software for any 54Srgrimes * purpose with or without fee is hereby granted, provided that the above 64Srgrimes * copyright notice and this permission notice appear in all copies. 74Srgrimes * 84Srgrimes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 94Srgrimes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 104Srgrimes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 114Srgrimes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 124Srgrimes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 134Srgrimes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 144Srgrimes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 154Srgrimes */ 164Srgrimes// Test 174Srgrimes// 1) read and lseek on every file in /proc 184Srgrimes// 2) readlink of every symlink in /proc 194Srgrimes// 3) recursively (1) + (2) for every directory in /proc 204Srgrimes// 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs 214Srgrimes// 5) write to /proc/sysrq-trigger 224Srgrimes#undef NDEBUG 234Srgrimes#include <assert.h> 244Srgrimes#include <errno.h> 254Srgrimes#include <sys/types.h> 264Srgrimes#include <dirent.h> 274Srgrimes#include <stdbool.h> 284Srgrimes#include <stdlib.h> 294Srgrimes#include <stdio.h> 304Srgrimes#include <string.h> 314Srgrimes#include <sys/stat.h> 324Srgrimes#include <sys/vfs.h> 334Srgrimes#include <fcntl.h> 344Srgrimes#include <unistd.h> 354Srgrimes 364Srgrimes#include "proc.h" 374Srgrimes 38620Srgrimesstatic void f_reg(DIR *d, const char *filename) 3950477Speter{ 404Srgrimes char buf[4096]; 414Srgrimes int fd; 4287649Sguido ssize_t rv; 4387649Sguido 442056Swollman /* read from /proc/kmsg can block */ 451549Srgrimes fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK); 465764Sbde if (fd == -1) 4756525Sbde return; 4885448Sjlemon /* struct proc_ops::proc_lseek is mandatory if file is seekable. */ 4912675Sjulian (void)lseek(fd, 0, SEEK_SET); 5085373Sjlemon rv = read(fd, buf, sizeof(buf)); 5185373Sjlemon assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); 5269929Sobrien close(fd); 5385373Sjlemon} 5418951Sjulian 5512701Sphkstatic void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len) 562056Swollman{ 5734924Sbde int fd; 5885373Sjlemon ssize_t rv; 594Srgrimes 6087620Sguido fd = openat(dirfd(d), filename, O_WRONLY); 6187620Sguido if (fd == -1) 6212701Sphk return; 634Srgrimes rv = write(fd, buf, len); 6412675Sjulian assert((0 <= rv && rv <= len) || rv == -1); 6512675Sjulian close(fd); 6612675Sjulian} 6712675Sjulian 6812675Sjulianstatic void f_lnk(DIR *d, const char *filename) 6929368Speter{ 7072521Sjlemon char buf[4096]; 7112675Sjulian ssize_t rv; 7238485Sbde 7347625Sphk rv = readlinkat(dirfd(d), filename, buf, sizeof(buf)); 7447625Sphk assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); 7547625Sphk} 7647625Sphk 7747625Sphkstatic void f(DIR *d, unsigned int level) 7847625Sphk{ 7947625Sphk struct dirent *de; 8047625Sphk 8147625Sphk de = xreaddir(d); 8247625Sphk assert(de->d_type == DT_DIR); 8347625Sphk assert(streq(de->d_name, ".")); 8447625Sphk 8547625Sphk de = xreaddir(d); 8672521Sjlemon assert(de->d_type == DT_DIR); 8772521Sjlemon assert(streq(de->d_name, "..")); 8838485Sbde 8912675Sjulian while ((de = xreaddir(d))) { 9085373Sjlemon assert(!streq(de->d_name, ".")); 9185373Sjlemon assert(!streq(de->d_name, "..")); 9285373Sjlemon 9385373Sjlemon switch (de->d_type) { 9485373Sjlemon DIR *dd; 9585373Sjlemon int fd; 9685373Sjlemon 9785373Sjlemon case DT_REG: 9885373Sjlemon if (level == 0 && streq(de->d_name, "sysrq-trigger")) { 9985373Sjlemon f_reg_write(d, de->d_name, "h", 1); 10085373Sjlemon } else if (level == 1 && streq(de->d_name, "clear_refs")) { 10185373Sjlemon f_reg_write(d, de->d_name, "1", 1); 10285373Sjlemon } else if (level == 3 && streq(de->d_name, "clear_refs")) { 10385373Sjlemon f_reg_write(d, de->d_name, "1", 1); 10485373Sjlemon } else { 10585373Sjlemon f_reg(d, de->d_name); 10685373Sjlemon } 10749049Syokota break; 10841612Seivind case DT_DIR: 10949049Syokota fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY); 11027982Sjulian if (fd == -1) 1117680Sjoerg continue; 1127680Sjoerg dd = fdopendir(fd); 1137680Sjoerg if (!dd) 1147680Sjoerg continue; 11585373Sjlemon f(dd, level + 1); 11685373Sjlemon closedir(dd); 11785373Sjlemon break; 11856525Sbde case DT_LNK: 11987620Sguido f_lnk(d, de->d_name); 12087620Sguido break; 12187620Sguido default: 1225764Sbde assert(0); 12385448Sjlemon } 12485448Sjlemon } 12555823Syokota} 12678161Speter 12742373Syokotaint main(void) 128798Swollman{ 12985373Sjlemon DIR *d; 1304Srgrimes struct statfs sfs; 13185373Sjlemon 1324Srgrimes d = opendir("/proc"); 1334Srgrimes if (!d) 13418951Sjulian return 4; 13518951Sjulian 13618951Sjulian /* Ensure /proc is proc. */ 13718951Sjulian if (fstatfs(dirfd(d), &sfs) == -1) { 13818951Sjulian return 1; 13918951Sjulian } 14018951Sjulian if (sfs.f_type != 0x9fa0) { 14118951Sjulian fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type); 14218951Sjulian return 2; 14318951Sjulian } 14485373Sjlemon 14518951Sjulian f(d, 0); 14685373Sjlemon 1474Srgrimes return 0; 14885373Sjlemon} 14985373Sjlemon