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