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
usage(void)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
print_rule(struct fbd_rule * rule)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
do_list(int fd)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
scan_hex64(char * input,u64_t * val)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
scan_range(char * input,u64_t * start,u64_t * end,int need_end)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
do_add(int fd,int argc,char ** argv,int off)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
do_del(int fd,int argc,char ** argv,int off)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
main(int argc,char ** argv)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