320 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* fbdctl - FBD control tool - by D.C. van Moolenbroek */
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <minix/ioctl.h>
 | |
| #include <minix/u64.h>
 | |
| #include <sys/ioc_fbd.h>
 | |
| #include <unistd.h>
 | |
| #include <fcntl.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| static int usage(char *name)
 | |
| {
 | |
| 	printf("usage:\n");
 | |
| 	printf("  %s list\n", name);
 | |
| 	printf("  %s add [-a start[-end]] [-s skip] [-c count] [-rw] "
 | |
| 		"<action> [params]\n", name);
 | |
| 	printf("  %s del N\n", name);
 | |
| 	printf("\n");
 | |
| 	printf("actions and params:\n");
 | |
| 	printf("  corrupt [zero|persist|random]\n");
 | |
| 	printf("  error [OK|EIO]\n");
 | |
| 	printf("  misdir <start>-<end> <align>\n");
 | |
| 	printf("  lost\n");
 | |
| 	printf("  torn <lead>\n");
 | |
| 	printf("use %s -d <device> to specify a device other than /dev/fbd\n",
 | |
| 		name);
 | |
| 
 | |
| 	return EXIT_FAILURE;
 | |
| }
 | |
| 
 | |
| static void print_rule(struct fbd_rule *rule)
 | |
| {
 | |
| 	printf("%-2d %04lX%08lX-%04lX%08lX %-4d %-5d %c%c ",
 | |
| 		rule->num, ex64hi(rule->start), ex64lo(rule->start),
 | |
| 		ex64hi(rule->end), ex64lo(rule->end), rule->skip,
 | |
| 		rule->count, (rule->flags & FBD_FLAG_READ) ? 'r' : ' ',
 | |
| 		(rule->flags & FBD_FLAG_WRITE) ? 'w' : ' ');
 | |
| 
 | |
| 	switch (rule->action) {
 | |
| 	case FBD_ACTION_CORRUPT:
 | |
| 		printf("%-7s ", "corrupt");
 | |
| 		switch (rule->params.corrupt.type) {
 | |
| 		case FBD_CORRUPT_ZERO: printf("zero"); break;
 | |
| 		case FBD_CORRUPT_PERSIST: printf("persist"); break;
 | |
| 		case FBD_CORRUPT_RANDOM: printf("random"); break;
 | |
| 		default: printf("<unknown>");
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case FBD_ACTION_ERROR:
 | |
| 		printf("%-7s ", "error");
 | |
| 
 | |
| 		switch (rule->params.error.code) {
 | |
| 		case 0:
 | |
| 			printf("OK");
 | |
| 			break;
 | |
| 		case EIO:
 | |
| 		case -EIO:
 | |
| 			printf("EIO");
 | |
| 			break;
 | |
| 		default:
 | |
| 			printf("%d", rule->params.error.code);
 | |
| 		}
 | |
| 
 | |
| 		break;
 | |
| 
 | |
| 	case FBD_ACTION_MISDIR:
 | |
| 		printf("%-7s %04lX%08lX-%04lX%08lX %u",
 | |
| 			"misdir", ex64hi(rule->params.misdir.start),
 | |
| 			ex64lo(rule->params.misdir.start),
 | |
| 			ex64hi(rule->params.misdir.end),
 | |
| 			ex64lo(rule->params.misdir.end),
 | |
| 			rule->params.misdir.align);
 | |
| 		break;
 | |
| 
 | |
| 	case FBD_ACTION_LOSTTORN:
 | |
| 		if (rule->params.losttorn.lead > 0)
 | |
| 			printf("%-7s %u", "torn",
 | |
| 				rule->params.losttorn.lead);
 | |
| 		else
 | |
| 			printf("%-7s", "lost");
 | |
| 	}
 | |
| 
 | |
| 	printf("\n");
 | |
| }
 | |
| 
 | |
| static int do_list(int fd)
 | |
| {
 | |
| 	struct fbd_rule rule;
 | |
| 	int i;
 | |
| 
 | |
| 	printf("N  Start        End          Skip Count RW Action  Params\n");
 | |
| 
 | |
| 	for (i = 1; ; i++) {
 | |
| 		rule.num = i;
 | |
| 
 | |
| 		if (ioctl(fd, FBDCGETRULE, &rule) < 0) {
 | |
| 			if (errno == ENOENT)
 | |
| 				continue;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		print_rule(&rule);
 | |
| 	}
 | |
| 
 | |
| 	return EXIT_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int scan_hex64(char *input, u64_t *val)
 | |
| {
 | |
| 	u32_t lo, hi;
 | |
| 	char buf[9];
 | |
| 	int len;
 | |
| 
 | |
| 	len = strlen(input);
 | |
| 
 | |
| 	if (len < 1 || len > 16) return 0;
 | |
| 
 | |
| 	if (len > 8) {
 | |
| 		memcpy(buf, input, len - 8);
 | |
| 		buf[len - 8] = 0;
 | |
| 		input += len - 8;
 | |
| 
 | |
| 		hi = strtoul(buf, NULL, 16);
 | |
| 	}
 | |
| 	else hi = 0;
 | |
| 
 | |
| 	lo = strtoul(input, NULL, 16);
 | |
| 
 | |
| 	*val = make64(lo, hi);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| static int scan_range(char *input, u64_t *start, u64_t *end, int need_end)
 | |
| {
 | |
| 	char *p;
 | |
| 
 | |
| 	if ((p = strchr(input, '-')) != NULL) {
 | |
| 		*p++ = 0;
 | |
| 
 | |
| 		if (!scan_hex64(p, end)) return 0;
 | |
| 	}
 | |
| 	else if (need_end) return 0;
 | |
| 
 | |
| 	return scan_hex64(input, start);
 | |
| }
 | |
| 
 | |
| static int do_add(int fd, int argc, char **argv, int off)
 | |
| {
 | |
| 	struct fbd_rule rule;
 | |
| 	int c, r;
 | |
| 
 | |
| 	memset(&rule, 0, sizeof(rule));
 | |
| 
 | |
| 	while ((c = getopt(argc-off, argv+off, "a:s:c:rw")) != EOF) {
 | |
| 		switch (c) {
 | |
| 		case 'a':
 | |
| 			if (!scan_range(optarg, &rule.start, &rule.end, 0))
 | |
| 				return usage(argv[0]);
 | |
| 			break;
 | |
| 		case 's':
 | |
| 			rule.skip = atoi(optarg);
 | |
| 			break;
 | |
| 		case 'c':
 | |
| 			rule.count = atoi(optarg);
 | |
| 			break;
 | |
| 		case 'r':
 | |
| 			rule.flags |= FBD_FLAG_READ;
 | |
| 			break;
 | |
| 		case 'w':
 | |
| 			rule.flags |= FBD_FLAG_WRITE;
 | |
| 			break;
 | |
| 		default:
 | |
| 			return usage(argv[0]);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	optind += off; /* compensate for the shifted argc/argv */
 | |
| 
 | |
| 	if (optind >= argc) return usage(argv[0]);
 | |
| 
 | |
| 	/* default to reads and writes */
 | |
| 	if (!rule.flags) rule.flags = FBD_FLAG_READ | FBD_FLAG_WRITE;
 | |
| 
 | |
| 	if (!strcmp(argv[optind], "corrupt")) {
 | |
| 		if (optind+1 >= argc) return usage(argv[0]);
 | |
| 
 | |
| 		rule.action = FBD_ACTION_CORRUPT;
 | |
| 
 | |
| 		if (!strcmp(argv[optind+1], "zero"))
 | |
| 			rule.params.corrupt.type = FBD_CORRUPT_ZERO;
 | |
| 		else if (!strcmp(argv[optind+1], "persist"))
 | |
| 			rule.params.corrupt.type = FBD_CORRUPT_PERSIST;
 | |
| 		else if (!strcmp(argv[optind+1], "random"))
 | |
| 			rule.params.corrupt.type = FBD_CORRUPT_RANDOM;
 | |
| 		else return usage(argv[0]);
 | |
| 	}
 | |
| 	else if (!strcmp(argv[optind], "error")) {
 | |
| 		if (optind+1 >= argc) return usage(argv[0]);
 | |
| 
 | |
| 		rule.action = FBD_ACTION_ERROR;
 | |
| 
 | |
| 		if (!strcmp(argv[optind+1], "OK"))
 | |
| 			rule.params.error.code = 0;
 | |
| 		else if (!strcmp(argv[optind+1], "EIO")) {
 | |
| 			if (EIO > 0)
 | |
| 				rule.params.error.code = -EIO;
 | |
| 			else
 | |
| 				rule.params.error.code = EIO;
 | |
| 		}
 | |
| 		else return usage(argv[0]);
 | |
| 	}
 | |
| 	else if (!strcmp(argv[optind], "misdir")) {
 | |
| 		if (optind+2 >= argc) return usage(argv[0]);
 | |
| 
 | |
| 		rule.action = FBD_ACTION_MISDIR;
 | |
| 
 | |
| 		if (!scan_range(argv[optind+1], &rule.params.misdir.start,
 | |
| 				&rule.params.misdir.end, 1))
 | |
| 			return usage(argv[0]);
 | |
| 
 | |
| 		rule.params.misdir.align = atoi(argv[optind+2]);
 | |
| 
 | |
| 		if ((int) rule.params.misdir.align <= 0)
 | |
| 			return usage(argv[0]);
 | |
| 	}
 | |
| 	else if (!strcmp(argv[optind], "lost")) {
 | |
| 		rule.action = FBD_ACTION_LOSTTORN;
 | |
| 
 | |
| 		rule.params.losttorn.lead = 0;
 | |
| 	}
 | |
| 	else if (!strcmp(argv[optind], "torn")) {
 | |
| 		if (optind+1 >= argc) return usage(argv[0]);
 | |
| 
 | |
| 		rule.action = FBD_ACTION_LOSTTORN;
 | |
| 
 | |
| 		rule.params.losttorn.lead = atoi(argv[optind+1]);
 | |
| 
 | |
| 		if ((int) rule.params.losttorn.lead <= 0)
 | |
| 			return usage(argv[0]);
 | |
| 	}
 | |
| 	else return usage(argv[0]);
 | |
| 
 | |
| #if DEBUG
 | |
| 	print_rule(&rule);
 | |
| #endif
 | |
| 
 | |
| 	r = ioctl(fd, FBDCADDRULE, &rule);
 | |
| 
 | |
| 	if (r < 0) {
 | |
| 		perror("ioctl");
 | |
| 
 | |
| 		return EXIT_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	printf("Added rule %d\n", r);
 | |
| 
 | |
| 	return EXIT_SUCCESS;
 | |
| }
 | |
| 
 | |
| static int do_del(int fd, int argc, char **argv, int off)
 | |
| {
 | |
| 	fbd_rulenum_t num;
 | |
| 
 | |
| 	if (argc < off + 2)
 | |
| 		return usage(argv[0]);
 | |
| 
 | |
| 	num = atoi(argv[off + 1]);
 | |
| 
 | |
| 	if (ioctl(fd, FBDCDELRULE, &num)) {
 | |
| 		perror("ioctl");
 | |
| 
 | |
| 		return EXIT_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	printf("Deleted rule %d\n", num);
 | |
| 
 | |
| 	return EXIT_SUCCESS;
 | |
| }
 | |
| 
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
| 	int r, fd, off = 1;
 | |
| 	char *dev = "/dev/fbd";
 | |
| 
 | |
| 	if (argc < 2)
 | |
| 		return usage(argv[0]);
 | |
| 
 | |
| 	if (!strcmp(argv[1], "-d")) {
 | |
| 		if (argc < 4)
 | |
| 			return usage(argv[0]);
 | |
| 
 | |
| 		dev = argv[2];
 | |
| 
 | |
| 		off += 2;
 | |
| 	}
 | |
| 
 | |
| 	fd = open(dev, O_RDONLY);
 | |
| 	if (fd < 0) {
 | |
| 		perror(dev);
 | |
| 
 | |
| 		return EXIT_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	else if (!strcmp(argv[off], "list"))
 | |
| 		r = do_list(fd);
 | |
| 	else if (!strcmp(argv[off], "add"))
 | |
| 		r = do_add(fd, argc, argv, off);
 | |
| 	else if (!strcmp(argv[off], "del"))
 | |
| 		r = do_del(fd, argc, argv, off);
 | |
| 	else
 | |
| 		r = usage(argv[0]);
 | |
| 
 | |
| 	close(fd);
 | |
| 
 | |
| 	return r;
 | |
| }
 | 
