148 lines · 3.5 KB · C
RawDownload
/* * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */// Test// 1) read and lseek on every file in /proc// 2) readlink of every symlink in /proc// 3) recursively (1) + (2) for every directory in /proc// 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs// 5) write to /proc/sysrq-trigger#undef NDEBUG#include <assert.h>#include <errno.h>#include <sys/types.h>#include <dirent.h>#include <stdbool.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <sys/vfs.h>#include <fcntl.h>#include <unistd.h> #include "proc.h" static void f_reg(DIR *d, const char *filename){	char buf[4096];	int fd;	ssize_t rv; 	/* read from /proc/kmsg can block */	fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK);	if (fd == -1)		return;	/* struct proc_ops::proc_lseek is mandatory if file is seekable. */	(void)lseek(fd, 0, SEEK_SET);	rv = read(fd, buf, sizeof(buf));	assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);	close(fd);} static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len){	int fd;	ssize_t rv; 	fd = openat(dirfd(d), filename, O_WRONLY);	if (fd == -1)		return;	rv = write(fd, buf, len);	assert((0 <= rv && rv <= len) || rv == -1);	close(fd);} static void f_lnk(DIR *d, const char *filename){	char buf[4096];	ssize_t rv; 	rv = readlinkat(dirfd(d), filename, buf, sizeof(buf));	assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);} static void f(DIR *d, unsigned int level){	struct dirent *de; 	de = xreaddir(d);	assert(de->d_type == DT_DIR);	assert(streq(de->d_name, ".")); 	de = xreaddir(d);	assert(de->d_type == DT_DIR);	assert(streq(de->d_name, "..")); 	while ((de = xreaddir(d))) {		assert(!streq(de->d_name, "."));		assert(!streq(de->d_name, "..")); 		switch (de->d_type) {			DIR *dd;			int fd; 		case DT_REG:			if (level == 0 && streq(de->d_name, "sysrq-trigger")) {				f_reg_write(d, de->d_name, "h", 1);			} else if (level == 1 && streq(de->d_name, "clear_refs")) {				f_reg_write(d, de->d_name, "1", 1);			} else if (level == 3 && streq(de->d_name, "clear_refs")) {				f_reg_write(d, de->d_name, "1", 1);			} else {				f_reg(d, de->d_name);			}			break;		case DT_DIR:			fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY);			if (fd == -1)				continue;			dd = fdopendir(fd);			if (!dd)				continue;			f(dd, level + 1);			closedir(dd);			break;		case DT_LNK:			f_lnk(d, de->d_name);			break;		default:			assert(0);		}	}} int main(void){	DIR *d;	struct statfs sfs; 	d = opendir("/proc");	if (!d)		return 4; 	/* Ensure /proc is proc. */	if (fstatfs(dirfd(d), &sfs) == -1) {		return 1;	}	if (sfs.f_type != 0x9fa0) {		fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type);		return 2;	} 	f(d, 0); 	return 0;}