xref: /minix/minix/usr.sbin/fbdctl/fbdctl.c (revision 9f988b79)
1 /* fbdctl - FBD control tool - by D.C. van Moolenbroek */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <minix/u64.h>
6 #include <sys/ioctl.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 
11 #define PATH_DEV_FBD	"/dev/fbd"
12 
13 static void __dead
14 usage(void)
15 {
16 
17 	fprintf(stderr, "usage:\n");
18 	fprintf(stderr, "  %s list\n", getprogname());
19 	fprintf(stderr, "  %s add [-a start[-end]] [-s skip] [-c count] [-rw] "
20 	    "<action> [params]\n", getprogname());
21 	fprintf(stderr, "  %s del N\n", getprogname());
22 	fprintf(stderr, "\n");
23 	fprintf(stderr, "actions and params:\n");
24 	fprintf(stderr, "  corrupt [zero|persist|random]\n");
25 	fprintf(stderr, "  error [OK|EIO]\n");
26 	fprintf(stderr, "  misdir <start>-<end> <align>\n");
27 	fprintf(stderr, "  lost\n");
28 	fprintf(stderr, "  torn <lead>\n");
29 	fprintf(stderr, "use %s -d <device> to specify a device other than "
30 	    "%s\n", getprogname(), PATH_DEV_FBD);
31 
32 	exit(EXIT_FAILURE);
33 }
34 
35 static void
36 print_rule(struct fbd_rule * rule)
37 {
38 	printf("%-2d %04lX%08lX-%04lX%08lX %-4d %-5d %c%c ",
39 	    rule->num, ex64hi(rule->start), ex64lo(rule->start),
40 	    ex64hi(rule->end), ex64lo(rule->end), rule->skip,
41 	    rule->count, (rule->flags & FBD_FLAG_READ) ? 'r' : ' ',
42 	    (rule->flags & FBD_FLAG_WRITE) ? 'w' : ' ');
43 
44 	switch (rule->action) {
45 	case FBD_ACTION_CORRUPT:
46 		printf("%-7s ", "corrupt");
47 		switch (rule->params.corrupt.type) {
48 		case FBD_CORRUPT_ZERO: printf("zero"); break;
49 		case FBD_CORRUPT_PERSIST: printf("persist"); break;
50 		case FBD_CORRUPT_RANDOM: printf("random"); break;
51 		default: printf("<unknown>");
52 		}
53 		break;
54 
55 	case FBD_ACTION_ERROR:
56 		printf("%-7s ", "error");
57 
58 		switch (rule->params.error.code) {
59 		case 0:
60 			printf("OK");
61 			break;
62 		case EIO:
63 		case -EIO:
64 			printf("EIO");
65 			break;
66 		default:
67 			printf("%d", rule->params.error.code);
68 		}
69 
70 		break;
71 
72 	case FBD_ACTION_MISDIR:
73 		printf("%-7s %04lX%08lX-%04lX%08lX %u",
74 		    "misdir", ex64hi(rule->params.misdir.start),
75 		    ex64lo(rule->params.misdir.start),
76 		    ex64hi(rule->params.misdir.end),
77 		    ex64lo(rule->params.misdir.end),
78 		    rule->params.misdir.align);
79 		break;
80 
81 	case FBD_ACTION_LOSTTORN:
82 		if (rule->params.losttorn.lead > 0)
83 			printf("%-7s %u", "torn", rule->params.losttorn.lead);
84 		else
85 			printf("%-7s", "lost");
86 	}
87 
88 	printf("\n");
89 }
90 
91 static int
92 do_list(int fd)
93 {
94 	struct fbd_rule rule;
95 	int i;
96 
97 	printf("N  Start        End          Skip Count RW Action  Params\n");
98 
99 	for (i = 1; ; i++) {
100 		rule.num = i;
101 
102 		if (ioctl(fd, FBDCGETRULE, &rule) < 0) {
103 			if (errno == ENOENT)
104 				continue;
105 			break;
106 		}
107 
108 		print_rule(&rule);
109 	}
110 
111 	return EXIT_SUCCESS;
112 }
113 
114 static int
115 scan_hex64(char * input, u64_t * val)
116 {
117 	u32_t lo, hi;
118 	char buf[9];
119 	int len;
120 
121 	len = strlen(input);
122 
123 	if (len < 1 || len > 16) return 0;
124 
125 	if (len > 8) {
126 		memcpy(buf, input, len - 8);
127 		buf[len - 8] = 0;
128 		input += len - 8;
129 
130 		hi = strtoul(buf, NULL, 16);
131 	}
132 	else hi = 0;
133 
134 	lo = strtoul(input, NULL, 16);
135 
136 	*val = make64(lo, hi);
137 
138 	return 1;
139 }
140 
141 static int
142 scan_range(char * input, u64_t * start, u64_t * end, int need_end)
143 {
144 	char *p;
145 
146 	if ((p = strchr(input, '-')) != NULL) {
147 		*p++ = 0;
148 
149 		if (!scan_hex64(p, end)) return 0;
150 	}
151 	else if (need_end) return 0;
152 
153 	return scan_hex64(input, start);
154 }
155 
156 static int
157 do_add(int fd, int argc, char ** argv, int off)
158 {
159 	struct fbd_rule rule;
160 	int c, r;
161 
162 	memset(&rule, 0, sizeof(rule));
163 
164 	while ((c = getopt(argc-off, argv+off, "a:s:c:rw")) != EOF) {
165 		switch (c) {
166 		case 'a':
167 			if (!scan_range(optarg, &rule.start, &rule.end, 0))
168 				usage();
169 			break;
170 		case 's':
171 			rule.skip = atoi(optarg);
172 			break;
173 		case 'c':
174 			rule.count = atoi(optarg);
175 			break;
176 		case 'r':
177 			rule.flags |= FBD_FLAG_READ;
178 			break;
179 		case 'w':
180 			rule.flags |= FBD_FLAG_WRITE;
181 			break;
182 		default:
183 			usage();
184 		}
185 	}
186 
187 	optind += off; /* compensate for the shifted argc/argv */
188 
189 	if (optind >= argc) usage();
190 
191 	/* default to reads and writes */
192 	if (!rule.flags) rule.flags = FBD_FLAG_READ | FBD_FLAG_WRITE;
193 
194 	if (!strcmp(argv[optind], "corrupt")) {
195 		if (optind+1 >= argc) usage();
196 
197 		rule.action = FBD_ACTION_CORRUPT;
198 
199 		if (!strcmp(argv[optind+1], "zero"))
200 			rule.params.corrupt.type = FBD_CORRUPT_ZERO;
201 		else if (!strcmp(argv[optind+1], "persist"))
202 			rule.params.corrupt.type = FBD_CORRUPT_PERSIST;
203 		else if (!strcmp(argv[optind+1], "random"))
204 			rule.params.corrupt.type = FBD_CORRUPT_RANDOM;
205 		else usage();
206 	}
207 	else if (!strcmp(argv[optind], "error")) {
208 		if (optind+1 >= argc) usage();
209 
210 		rule.action = FBD_ACTION_ERROR;
211 
212 		if (!strcmp(argv[optind+1], "OK"))
213 			rule.params.error.code = 0;
214 		else if (!strcmp(argv[optind+1], "EIO")) {
215 			if (EIO > 0)
216 				rule.params.error.code = -EIO;
217 			else
218 				rule.params.error.code = EIO;
219 		}
220 		else usage();
221 	}
222 	else if (!strcmp(argv[optind], "misdir")) {
223 		if (optind+2 >= argc) usage();
224 
225 		rule.action = FBD_ACTION_MISDIR;
226 
227 		if (!scan_range(argv[optind+1], &rule.params.misdir.start,
228 		    &rule.params.misdir.end, 1))
229 			usage();
230 
231 		rule.params.misdir.align = atoi(argv[optind+2]);
232 
233 		if ((int)rule.params.misdir.align <= 0)
234 			usage();
235 	}
236 	else if (!strcmp(argv[optind], "lost")) {
237 		rule.action = FBD_ACTION_LOSTTORN;
238 
239 		rule.params.losttorn.lead = 0;
240 	}
241 	else if (!strcmp(argv[optind], "torn")) {
242 		if (optind+1 >= argc) usage();
243 
244 		rule.action = FBD_ACTION_LOSTTORN;
245 
246 		rule.params.losttorn.lead = atoi(argv[optind+1]);
247 
248 		if ((int)rule.params.losttorn.lead <= 0)
249 			usage();
250 	}
251 	else usage();
252 
253 #if DEBUG
254 	print_rule(&rule);
255 #endif
256 
257 	r = ioctl(fd, FBDCADDRULE, &rule);
258 
259 	if (r < 0) {
260 		perror("ioctl");
261 
262 		return EXIT_FAILURE;
263 	}
264 
265 	printf("Added rule %d\n", r);
266 
267 	return EXIT_SUCCESS;
268 }
269 
270 static int
271 do_del(int fd, int argc, char ** argv, int off)
272 {
273 	fbd_rulenum_t num;
274 
275 	if (argc < off + 2)
276 		usage();
277 
278 	num = atoi(argv[off + 1]);
279 
280 	if (ioctl(fd, FBDCDELRULE, &num)) {
281 		perror("ioctl");
282 
283 		return EXIT_FAILURE;
284 	}
285 
286 	printf("Deleted rule %d\n", num);
287 
288 	return EXIT_SUCCESS;
289 }
290 
291 int
292 main(int argc, char ** argv)
293 {
294 	int r, fd, off = 1;
295 	const char *dev = PATH_DEV_FBD;
296 
297 	setprogname(argv[0]);
298 
299 	if (argc < 2)
300 		usage();
301 
302 	if (!strcmp(argv[1], "-d")) {
303 		if (argc < 4)
304 			usage();
305 
306 		dev = argv[2];
307 
308 		off += 2;
309 	}
310 
311 	fd = open(dev, O_RDONLY);
312 	if (fd < 0) {
313 		perror(dev);
314 
315 		return EXIT_FAILURE;
316 	}
317 
318 	if (!strcmp(argv[off], "list"))
319 		r = do_list(fd);
320 	else if (!strcmp(argv[off], "add"))
321 		r = do_add(fd, argc, argv, off);
322 	else if (!strcmp(argv[off], "del"))
323 		r = do_del(fd, argc, argv, off);
324 	else
325 		usage();
326 
327 	close(fd);
328 
329 	return r;
330 }
331