⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tests.c

📁 mtd-utils 是一套更改linux mtd設備的工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2007 Nokia Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Author: Adrian Hunter */#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <stdint.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <sys/vfs.h>#include <sys/statvfs.h>#include <linux/jffs2.h>#include <libgen.h>#include <dirent.h>#include <ctype.h>#include <limits.h>#include <sys/mount.h>#include <mntent.h>#include <time.h>#include "tests.h"char *tests_file_system_mount_dir = TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR;char *tests_file_system_type = TESTS_DEFAULT_FILE_SYSTEM_TYPE;int tests_ok_to_sync = 0; /* Whether to use fsync *//* General purpose test parameter to specify some aspect of test size.   May be used by different tests in different ways or not at all.   Set by the -z or --size option. */int64_t tests_size_parameter = 0;/* General purpose test parameter to specify some aspect of test repetition.   May be used by different tests in different ways or not at all.   Set by the -n, --repeat options. */int64_t tests_repeat_parameter = 0;/* General purpose test parameter to specify some aspect of test sleeping.   May be used by different tests in different ways or not at all.   Set by the -p, --sleep options. */int64_t tests_sleep_parameter = 0;/* Program name from argv[0] */char *program_name = "unknown";/* General purpose test parameter to specify a file should be unlinked.   May be used by different tests in different ways or not at all. */int tests_unlink_flag = 0;/* General purpose test parameter to specify a file should be closed.   May be used by different tests in different ways or not at all. */int tests_close_flag = 0;/* General purpose test parameter to specify a file should be deleted.   May be used by different tests in different ways or not at all. */int tests_delete_flag = 0;/* General purpose test parameter to specify a file have a hole.   May be used by different tests in different ways or not at all. */int tests_hole_flag = 0;/* Whether it is ok to test on the root file system */static int rootok = 0;/* Maximum file name length of test file system (from statfs) */long tests_max_fname_len = 255;/* Function invoked by the CHECK macro */void tests_test(int test,const char *msg,const char *file,unsigned line){	int eno;	time_t t;	if (test)		return;	eno = errno;	time(&t);	fprintf(stderr,	"Test failed: %s on %s"			"Test failed: %s in %s at line %u\n",			program_name, ctime(&t), msg, file, line);	if (eno) {		fprintf(stderr,"errno = %d\n",eno);		fprintf(stderr,"strerror = %s\n",strerror(eno));	}	exit(1);}static int is_zero(const char *p){	for (;*p;++p)		if (*p != '0')			return 0;	return 1;}static void fold(const char *text, int width){	int pos, bpos = 0;	const char *p;	char line[1024];	if (width > 1023) {		printf("%s\n", text);		return;	}	p = text;	pos = 0;	while (p[pos]) {		while (!isspace(p[pos])) {			line[pos] = p[pos];			if (!p[pos])				break;			++pos;			if (pos == width) {				line[pos] = '\0';				printf("%s\n", line);				p += pos;				pos = 0;			}		}		while (pos < width) {			line[pos] = p[pos];			if (!p[pos]) {				bpos = pos;				break;			}			if (isspace(p[pos]))				bpos = pos;			++pos;		}		line[bpos] = '\0';		printf("%s\n", line);		p += bpos;		pos = 0;		while (p[pos] && isspace(p[pos]))			++p;	}}/* Handle common program options */int tests_get_args(int argc,		char *argv[],		const char *title,		const char *desc,		const char *opts){	int run_test = 0;	int display_help = 0;	int display_title = 0;	int display_description = 0;	int i;	char *s;	program_name = argv[0];	s = getenv("TEST_FILE_SYSTEM_MOUNT_DIR");	if (s)		tests_file_system_mount_dir = strdup(s);	s = getenv("TEST_FILE_SYSTEM_TYPE");	if (s)		tests_file_system_type = strdup(s);	run_test = 1;	rootok = 1;	for (i = 1; i < argc; ++i) {		if (strcmp(argv[i], "--help") == 0 ||				strcmp(argv[i], "-h") == 0)			display_help = 1;		else if (strcmp(argv[i], "--title") == 0 ||				strcmp(argv[i], "-t") == 0)			display_title = 1;		else if (strcmp(argv[i], "--description") == 0 ||				strcmp(argv[i], "-d") == 0)			display_description = 1;		else if (strcmp(argv[i], "--sync") == 0 ||				strcmp(argv[i], "-s") == 0)			tests_ok_to_sync = 1;		else if (strncmp(argv[i], "--size", 6) == 0 ||				strncmp(argv[i], "-z", 2) == 0) {			int64_t n;			char *p;			if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1]))				++i;			p = argv[i];			while (*p && !isdigit(*p))				++p;			n = atoll(p);			if (n)				tests_size_parameter = n;			else {				int all_zero = 1;				for (; all_zero && *p; ++p)					if (*p != '0')						all_zero = 0;				if (all_zero)					tests_size_parameter = 0;				else					display_help = 1;			}		} else if (strncmp(argv[i], "--repeat", 8) == 0 ||				strncmp(argv[i], "-n", 2) == 0) {			int64_t n;			char *p;			if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1]))				++i;			p = argv[i];			while (*p && !isdigit(*p))				++p;			n = atoll(p);			if (n || is_zero(p))				tests_repeat_parameter = n;			else				display_help = 1;		} else if (strncmp(argv[i], "--sleep", 7) == 0 ||				strncmp(argv[i], "-p", 2) == 0) {			int64_t n;			char *p;			if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1]))				++i;			p = argv[i];			while (*p && !isdigit(*p))				++p;			n = atoll(p);			if (n || is_zero(p))				tests_sleep_parameter = n;			else				display_help = 1;		} else if (strcmp(argv[i], "--unlink") == 0 ||				strcmp(argv[i], "-u") == 0)			tests_unlink_flag = 1;		else if (strcmp(argv[i], "--hole") == 0 ||				strcmp(argv[i], "-o") == 0)			tests_hole_flag = 1;		else if (strcmp(argv[i], "--close") == 0 ||				strcmp(argv[i], "-c") == 0)			tests_close_flag = 1;		else if (strcmp(argv[i], "--delete") == 0 ||				strcmp(argv[i], "-e") == 0)			tests_delete_flag = 1;		else			display_help = 1;	}	if (display_help) {		run_test = 0;		display_title = 0;		display_description = 0;		if (!opts)			opts = "";		printf("File System Test Program\n\n");		printf("Test Title: %s\n\n", title);		printf("Usage is: %s [ options ]\n",argv[0]);		printf("    Options are:\n");		printf("        -h, --help            ");		printf("Display this help\n");		printf("        -t, --title           ");		printf("Display the test title\n");		printf("        -d, --description     ");		printf("Display the test description\n");		if (strchr(opts, 's')) {			printf("        -s, --sync            ");			printf("Make use of fsync\n");		}		if (strchr(opts, 'z')) {			printf("        -z, --size            ");			printf("Set size parameter\n");		}		if (strchr(opts, 'n')) {			printf("        -n, --repeat          ");			printf("Set repeat parameter\n");		}		if (strchr(opts, 'p')) {			printf("        -p, --sleep           ");			printf("Set sleep parameter\n");		}		if (strchr(opts, 'u')) {			printf("        -u, --unlink          ");			printf("Unlink file\n");		}		if (strchr(opts, 'o')) {			printf("        -o, --hole            ");			printf("Create a hole in a file\n");		}		if (strchr(opts, 'c')) {			printf("        -c, --close           ");			printf("Close file\n");		}		if (strchr(opts, 'e')) {			printf("        -e, --delete          ");			printf("Delete file\n");		}		printf("\nBy default, testing is done in directory ");		printf("/mnt/test_file_system. To change this\nuse ");		printf("environmental variable ");		printf("TEST_FILE_SYSTEM_MOUNT_DIR. By default, ");		printf("the file\nsystem tested is jffs2. To change this ");		printf("set TEST_FILE_SYSTEM_TYPE.\n\n");		printf("Test Description:\n");		fold(desc, 80);	} else {		if (display_title)			printf("%s\n", title);		if (display_description)			printf("%s\n", desc);		if (display_title || display_description)			if (argc == 2 || (argc == 3 &&					display_title &&					display_description))				run_test = 0;	}	return run_test;}/* Return the number of files (or directories) in the given directory */unsigned tests_count_files_in_dir(const char *dir_name){	DIR *dir;	struct dirent *entry;	unsigned count = 0;	dir = opendir(dir_name);	CHECK(dir != NULL);	for (;;) {		errno = 0;		entry = readdir(dir);		if (entry) {			if (strcmp(".",entry->d_name) != 0 &&					strcmp("..",entry->d_name) != 0)				++count;		} else {			CHECK(errno == 0);			break;		}	}	CHECK(closedir(dir) != -1);	return count;}/* Change to the file system mount directory, check that it is empty,   matches the file system type, and is not the root file system */void tests_check_test_file_system(void){	struct statfs fs_info;	struct stat f_info;	struct stat root_f_info;	if (chdir(tests_file_system_mount_dir) == -1 ||			statfs(tests_file_system_mount_dir, &fs_info) == -1) {		fprintf(stderr, "Invalid test file system mount directory:"			" %s\n", tests_file_system_mount_dir);		fprintf(stderr,	"Use environment variable "			"TEST_FILE_SYSTEM_MOUNT_DIR\n");		CHECK(0);	}	tests_max_fname_len = fs_info.f_namelen;	if (strcmp(tests_file_system_type, "jffs2") == 0 &&			fs_info.f_type != JFFS2_SUPER_MAGIC) {		fprintf(stderr,	"File system type is not jffs2\n");		CHECK(0);	}	/* Check that the test file system is not the root file system */	if (!rootok) {		CHECK(stat(tests_file_system_mount_dir, &f_info) != -1);		CHECK(stat("/", &root_f_info) != -1);		CHECK(f_info.st_dev != root_f_info.st_dev);	}}/* Get the free space for the file system of the current directory */uint64_t tests_get_free_space(void){	struct statvfs fs_info;	CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1);	return (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize;}/* Get the total space for the file system of the current directory */uint64_t tests_get_total_space(void){	struct statvfs fs_info;	CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1);	return (uint64_t) fs_info.f_blocks * (uint64_t) fs_info.f_frsize;}#define WRITE_BUFFER_SIZE 32768static char write_buffer[WRITE_BUFFER_SIZE];static void init_write_buffer(){	static int init = 0;	if (!init) {		int i, d;		uint64_t u;		u = RAND_MAX;		u += 1;		u /= 256;		d = (int) u;		srand(1);		for (i = 0; i < WRITE_BUFFER_SIZE; ++i)			write_buffer[i] = rand() / d;		init = 1;	}}/* Write size random bytes into file descriptor fd at the current position,   returning the number of bytes actually written */uint64_t tests_fill_file(int fd, uint64_t size){	ssize_t written;	size_t sz;	unsigned start = 0, length;	uint64_t remains;	uint64_t actual_size = 0;	init_write_buffer();	remains = size;	while (remains > 0) {		length = WRITE_BUFFER_SIZE - start;		if (remains > length)			sz = length;		else			sz = (size_t) remains;		written = write(fd, write_buffer + start, sz);		if (written <= 0) {			CHECK(errno == ENOSPC); /* File system full */			errno = 0;			break;		}		remains -= written;		actual_size += written;		if (written == sz)			start = 0;		else			start += written;	}	tests_maybe_sync(fd);	return actual_size;}/* Write size random bytes into file descriptor fd at offset,   returning the number of bytes actually written */uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size){	ssize_t written;	size_t sz;	unsigned start = 0, length;	uint64_t remains;	uint64_t actual_size = 0;	CHECK(lseek(fd, offset, SEEK_SET) == offset);	init_write_buffer();	remains = size;	start = offset % WRITE_BUFFER_SIZE;	while (remains > 0) {		length = WRITE_BUFFER_SIZE - start;		if (remains > length)			sz = length;		else			sz = (size_t) remains;		written = write(fd, write_buffer + start, sz);		if (written <= 0) {			CHECK(errno == ENOSPC); /* File system full */			errno = 0;			break;		}		remains -= written;		actual_size += written;		if (written == sz)			start = 0;		else			start += written;	}	tests_maybe_sync(fd);	return actual_size;}/* Check that a file written using tests_fill_file() and/or   tests_write_filled_file() and/or tests_create_file()   contains the expected random data */void tests_check_filled_file_fd(int fd){	ssize_t sz;	char buf[WRITE_BUFFER_SIZE];	CHECK(lseek(fd, 0, SEEK_SET) == 0);	do {		sz = read(fd, buf, WRITE_BUFFER_SIZE);		CHECK(sz >= 0);		CHECK(memcmp(buf, write_buffer, sz) == 0);	} while (sz);}/* Check that a file written using tests_fill_file() and/or   tests_write_filled_file() and/or tests_create_file()   contains the expected random data */void tests_check_filled_file(const char *file_name){	int fd;	fd = open(file_name, O_RDONLY);	CHECK(fd != -1);	tests_check_filled_file_fd(fd);	CHECK(close(fd) != -1);}void tests_sync_directory(const char *file_name){	char *path;	char *dir;	int fd;	if (!tests_ok_to_sync)		return;	path = strdup(file_name);	dir = dirname(path);	fd = open(dir,O_RDONLY | tests_maybe_sync_flag());	CHECK(fd != -1);	CHECK(fsync(fd) != -1);	CHECK(close(fd) != -1);	free(path);}/* Delete a file */void tests_delete_file(const char *file_name){	CHECK(unlink(file_name) != -1);	tests_sync_directory(file_name);}/* Create a file of size file_size */uint64_t tests_create_file(const char *file_name, uint64_t file_size){	int fd;	int flags;	mode_t mode;	uint64_t actual_size; /* Less than size if the file system is full */	flags = O_CREAT | O_TRUNC | O_WRONLY | tests_maybe_sync_flag();	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;	fd = open(file_name, flags, mode);	if (fd == -1 && errno == ENOSPC) {		errno = 0;		return 0; /* File system full */	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -