fsck.c revision 4bf5fbfe055d5e9bce54a7bc2ad7b959041dcf12
1b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner/* 29368eea42a1afb01dd44110582f997115b50e742François Gaffie * pfsck --- A generic, parallelizing front-end for the fsck program. 3b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * It will automatically try to run fsck programs in parallel if the 4b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * devices are on separate spindles. It is based on the same ideas as 5b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * the generic front end for fsck by David Engel and Fred van Kempen, 6b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * but it has been completely rewritten from scratch to support 7b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * parallel execution. 8b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 9b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * Written by Theodore Ts'o, <tytso@mit.edu> 10b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 11b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * Usage: fsck [-AVRNTM] [-s] [-t fstype] [fs-options] device 12b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 13b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994: 14b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * o Changed -t fstype to behave like with mount when -A (all file 15b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * systems) or -M (like mount) is specified. 16b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * o fsck looks if it can find the fsck.type program to decide 17b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * if it should ignore the fs type. This way more fsck programs 18b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * can be added without changing this front-end. 19b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * o -R flag skip root file system. 20b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 21b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. 22b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 23b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * %Begin-Header% 24b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * This file may be redistributed under the terms of the GNU Public 25b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * License. 26b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * %End-Header% 27b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner */ 28b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner 2968a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/types.h> 3068a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/wait.h> 3168a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/signal.h> 3268a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/stat.h> 3368a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <limits.h> 3468a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <stdio.h> 359368eea42a1afb01dd44110582f997115b50e742François Gaffie#include <string.h> 369368eea42a1afb01dd44110582f997115b50e742François Gaffie#if HAVE_STDLIB_H 3768a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <stdlib.h> 38d9526499d6ab53b7d13d1434f748f6f2161c2e0aSebastien Gonzalve#endif 3968a912857707864bbaaff9808717813105072a6ePatrick Benavoli#if HAVE_ERRNO_H 409368eea42a1afb01dd44110582f997115b50e742François Gaffie#include <errno.h> 419368eea42a1afb01dd44110582f997115b50e742François Gaffie#endif 429368eea42a1afb01dd44110582f997115b50e742François Gaffie#if HAVE_MNTENT_H 4368a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <mntent.h> 4468a912857707864bbaaff9808717813105072a6ePatrick Benavoli#endif 459368eea42a1afb01dd44110582f997115b50e742François Gaffie#if HAVE_UNISTD_H 469368eea42a1afb01dd44110582f997115b50e742François Gaffie#include <unistd.h> 4768a912857707864bbaaff9808717813105072a6ePatrick Benavoli#endif 4868a912857707864bbaaff9808717813105072a6ePatrick Benavoli#if HAVE_ERRNO_H 4968a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <errno.h> 50b71ccf75a1b2c718543783b277bb9c104c97e490Patrick Benavoli#endif 5168a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <malloc.h> 5268a912857707864bbaaff9808717813105072a6ePatrick Benavoli 53d9526499d6ab53b7d13d1434f748f6f2161c2e0aSebastien Gonzalve#include "../version.h" 5468a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include "fsck.h" 559368eea42a1afb01dd44110582f997115b50e742François Gaffie 56daaa63ce33fa4795403f9339bc872694c9ab6113Frédéric Boisnardstatic const char *ignored_types[] = { 57daaa63ce33fa4795403f9339bc872694c9ab6113Frédéric Boisnard "ignore", 58daaa63ce33fa4795403f9339bc872694c9ab6113Frédéric Boisnard "iso9660", 5968a912857707864bbaaff9808717813105072a6ePatrick Benavoli "nfs", 6068a912857707864bbaaff9808717813105072a6ePatrick Benavoli "proc", 616ba361d96bc2581667b3400f87ff89fae6449e1fPatrick Benavoli "sw", 626ba361d96bc2581667b3400f87ff89fae6449e1fPatrick Benavoli "swap", 636ba361d96bc2581667b3400f87ff89fae6449e1fPatrick Benavoli NULL 646ba361d96bc2581667b3400f87ff89fae6449e1fPatrick Benavoli}; 656ba361d96bc2581667b3400f87ff89fae6449e1fPatrick Benavoli 666ba361d96bc2581667b3400f87ff89fae6449e1fPatrick Benavolistatic const char *really_wanted[] = { 67d9526499d6ab53b7d13d1434f748f6f2161c2e0aSebastien Gonzalve "minix", 6868a912857707864bbaaff9808717813105072a6ePatrick Benavoli "ext2", 6968a912857707864bbaaff9808717813105072a6ePatrick Benavoli "xiafs", 70d9526499d6ab53b7d13d1434f748f6f2161c2e0aSebastien Gonzalve NULL 710548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli}; 720548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli 730548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli#ifdef DEV_DSK_DEVICES 740548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavolistatic const char *base_devices[] = { 750548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli "/dev/dsk/hda", 760548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli "/dev/dsk/hdb", 770548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli "/dev/dsk/hdc", 780548523ab6bbca766dcce4be97a0c50efd529d90Patrick Benavoli "/dev/dsk/hdd", 799368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/hd1a", 809368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/hd1b", 8168a912857707864bbaaff9808717813105072a6ePatrick Benavoli "/dev/dsk/hd1c", 8268a912857707864bbaaff9808717813105072a6ePatrick Benavoli "/dev/dsk/hd1d", 839368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/sda", 8468a912857707864bbaaff9808717813105072a6ePatrick Benavoli "/dev/dsk/sdb", 859368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/sdc", 8668a912857707864bbaaff9808717813105072a6ePatrick Benavoli "/dev/dsk/sdd", 879368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/sde", 889368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/sdf", 899368eea42a1afb01dd44110582f997115b50e742François Gaffie "/dev/dsk/sdg", 909368eea42a1afb01dd44110582f997115b50e742François Gaffie NULL 919368eea42a1afb01dd44110582f997115b50e742François Gaffie}; 929368eea42a1afb01dd44110582f997115b50e742François Gaffie#else 93static const char *base_devices[] = { 94 "/dev/hda", 95 "/dev/hdb", 96 "/dev/hdc", 97 "/dev/hdd", 98 "/dev/hd1a", 99 "/dev/hd1b", 100 "/dev/hd1c", 101 "/dev/hd1d", 102 "/dev/sda", 103 "/dev/sdb", 104 "/dev/sdc", 105 "/dev/sdd", 106 "/dev/sde", 107 "/dev/sdf", 108 "/dev/sdg", 109 NULL 110}; 111#endif 112 113/* 114 * Global variables for options 115 */ 116char *devices[MAX_DEVICES]; 117char *args[MAX_ARGS]; 118int num_devices, num_args; 119 120int verbose = 0; 121int doall = 0; 122int noexecute = 0; 123int serialize = 0; 124int skip_root = 0; 125int like_mount = 0; 126int notitle = 0; 127int parallel_root = 0; 128char *progname; 129char *fstype = NULL; 130struct fs_info *filesys_info; 131struct fsck_instance *instance_list; 132const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc"; 133char *fsck_path = 0; 134static int ignore(struct fs_info *); 135 136#ifdef HAVE_STRDUP 137#ifdef _POSIX_SOURCE 138extern char *strdup(const char *s); 139#endif 140#else 141static char *strdup(const char *s) 142{ 143 char *ret; 144 145 ret = malloc(strlen(s)+1); 146 if (ret) 147 strcpy(ret, s); 148 return ret; 149} 150#endif 151 152static void free_instance(struct fsck_instance *i) 153{ 154 if (i->prog) 155 free(i->prog); 156 if (i->device) 157 free(i->device); 158 free(i); 159 return; 160} 161 162/* 163 * Load the filesystem database from /etc/fstab 164 */ 165static void load_fs_info(NOARGS) 166{ 167#if HAVE_MNTENT_H 168 FILE *mntfile; 169 struct mntent *mp; 170 struct fs_info *fs; 171 struct fs_info *fs_last = NULL; 172 int old_fstab = 1; 173 174 filesys_info = NULL; 175 176 /* Open the mount table. */ 177 if ((mntfile = setmntent(MNTTAB, "r")) == NULL) { 178 perror(MNTTAB); 179 exit(EXIT_ERROR); 180 } 181 182 while ((mp = getmntent(mntfile)) != NULL) { 183 fs = malloc(sizeof(struct fs_info)); 184 memset(fs, 0, sizeof(struct fs_info)); 185 fs->device = strdup(mp->mnt_fsname); 186 fs->mountpt = strdup(mp->mnt_dir); 187 fs->type = strdup(mp->mnt_type); 188 fs->opts = strdup(mp->mnt_opts); 189 fs->freq = mp->mnt_freq; 190 fs->passno = mp->mnt_passno; 191 fs->next = NULL; 192 if (!filesys_info) 193 filesys_info = fs; 194 else 195 fs_last->next = fs; 196 fs_last = fs; 197 if (fs->passno) 198 old_fstab = 0; 199 } 200 201 (void) endmntent(mntfile); 202 203 if (old_fstab) { 204 fprintf(stderr, "\007\007\007" 205 "WARNING: Your /etc/fstab does not contain the fsck passno\n"); 206 fprintf(stderr, 207 " field. I will kludge around things for you, but you\n"); 208 fprintf(stderr, 209 " should fix your /etc/fstab file as soon as you can.\n\n"); 210 211 for (fs = filesys_info; fs; fs = fs->next) { 212 fs->passno = 1; 213 } 214 } 215#else 216 filesys_info = NULL; 217#endif /* HAVE_MNTENT_H */ 218} 219 220/* Lookup filesys in /etc/fstab and return the corresponding entry. */ 221static struct fs_info *lookup(char *filesys) 222{ 223 struct fs_info *fs; 224 225 /* No filesys name given. */ 226 if (filesys == NULL) 227 return NULL; 228 229 for (fs = filesys_info; fs; fs = fs->next) { 230 if (!strcmp(filesys, fs->device) || 231 !strcmp(filesys, fs->mountpt)) 232 break; 233 } 234 235 return fs; 236} 237 238/* Find fsck program for a given fs type. */ 239static char *find_fsck(char *type) 240{ 241 char *s; 242 const char *tpl; 243 static char prog[256]; 244 char *p = strdup(fsck_path); 245 struct stat st; 246 247 /* Are we looking for a program or just a type? */ 248 tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s"); 249 250 for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) { 251 sprintf(prog, tpl, s, type); 252 if (stat(prog, &st) == 0) break; 253 } 254 free(p); 255 return(s ? prog : NULL); 256} 257 258/* 259 * Execute a particular fsck program, and link it into the list of 260 * child processes we are waiting for. 261 */ 262static int execute(char *prog, char *device) 263{ 264 char *s, *argv[80]; 265 int argc, i; 266 struct fsck_instance *inst; 267 pid_t pid; 268 269 argv[0] = strdup(prog); 270 argc = 1; 271 272 for (i=0; i <num_args; i++) 273 argv[argc++] = strdup(args[i]); 274 275 argv[argc++] = strdup(device); 276 argv[argc] = 0; 277 278 s = find_fsck(prog); 279 if (s == NULL) { 280 fprintf(stderr, "fsck: %s: not found\n", prog); 281 return ENOENT; 282 } 283 284 if (verbose || noexecute) { 285 printf("[%s] ", s); 286 for (i=0; i < argc; i++) 287 printf("%s ", argv[i]); 288 printf("\n"); 289 } 290 if (noexecute) 291 return 0; 292 293 /* Fork and execute the correct program. */ 294 if ((pid = fork()) < 0) { 295 perror("fork"); 296 return errno; 297 } else if (pid == 0) { 298 (void) execv(s, argv); 299 perror(argv[0]); 300 exit(EXIT_ERROR); 301 } 302 inst = malloc(sizeof(struct fsck_instance)); 303 if (!inst) 304 return ENOMEM; 305 memset(inst, 0, sizeof(struct fsck_instance)); 306 inst->pid = pid; 307 inst->prog = strdup(prog); 308 inst->device = strdup(device); 309 inst->next = instance_list; 310 instance_list = inst; 311 312 return 0; 313} 314 315/* 316 * Wait for one child process to exit; when it does, unlink it from 317 * the list of executing child processes, and return it. 318 */ 319static struct fsck_instance *wait_one(NOARGS) 320{ 321 int status; 322 int sig; 323 struct fsck_instance *inst, *prev; 324 pid_t pid; 325 326 if (!instance_list) 327 return NULL; 328 329retry: 330 pid = wait(&status); 331 if (pid < 0) { 332 if ((errno == EINTR) || (errno == EAGAIN)) 333 goto retry; 334 if (errno == ECHILD) { 335 fprintf(stderr, 336 "%s: wait: No more child process?!?\n", 337 progname); 338 return NULL; 339 } 340 perror("wait"); 341 goto retry; 342 } 343 for (prev = 0, inst = instance_list; 344 inst; 345 prev = inst, inst = inst->next) { 346 if (inst->pid == pid) 347 break; 348 } 349 if (!inst) { 350 printf("Unexpected child process %d, status = 0x%x\n", 351 pid, status); 352 goto retry; 353 } 354 if (WIFEXITED(status)) 355 status = WEXITSTATUS(status); 356 else if (WIFSIGNALED(status)) { 357 sig = WTERMSIG(status); 358 if (sig == SIGINT) { 359 status = EXIT_UNCORRECTED; 360 } else { 361 printf("Warning... %s for device %s exited " 362 "with signal %d.\n", 363 inst->prog, inst->device, sig); 364 status = EXIT_ERROR; 365 } 366 } else { 367 printf("%s %s: status is %x, should never happen.\n", 368 inst->prog, inst->device, status); 369 status = EXIT_ERROR; 370 } 371 inst->exit_status = status; 372 if (prev) 373 prev->next = inst->next; 374 else 375 instance_list = inst->next; 376 return inst; 377} 378 379/* 380 * Wait until all executing child processes have exited; return the 381 * logical OR of all of their exit code values. 382 */ 383static int wait_all(NOARGS) 384{ 385 struct fsck_instance *inst; 386 int global_status = 0; 387 388 while (instance_list) { 389 inst = wait_one(); 390 if (!inst) 391 break; 392 global_status |= inst->exit_status; 393 free_instance(inst); 394 } 395 return global_status; 396} 397 398/* 399 * Run the fsck program on a particular device 400 * 401 * If the type is specified using -t, and it isn't prefixed with "no" 402 * (as in "noext2") and only one filesystem type is specified, then 403 * use that type regardless of what is specified in /etc/fstab. 404 * 405 * If the type isn't specified by the user, then use either the type 406 * specified in /etc/fstab, or DEFAULT_FSTYPE. 407 */ 408static void fsck_device(char *device) 409{ 410 const char *type = 0; 411 struct fs_info *fsent; 412 int retval; 413 char prog[80]; 414 415 if (fstype && strncmp(fstype, "no", 2) && !strchr(fstype, ',')) 416 type = fstype; 417 418 if ((fsent = lookup(device))) { 419 device = fsent->device; 420 if (!type) 421 type = fsent->type; 422 } 423 if (!type) 424 type = DEFAULT_FSTYPE; 425 426 sprintf(prog, "fsck.%s", type); 427 retval = execute(prog, device); 428 if (retval) { 429 fprintf(stderr, "%s: Error %d while executing %s for %s\n", 430 progname, retval, prog, device); 431 } 432} 433 434/* See if filesystem type matches the list. */ 435static int fs_match(char *type, char *fs_type) 436{ 437 int ret = 0, negate = 0; 438 char list[128]; 439 char *s; 440 441 if (!fs_type) return(1); 442 443 if (strncmp(fs_type, "no", 2) == 0) { 444 fs_type += 2; 445 negate = 1; 446 } 447 strcpy(list, fs_type); 448 s = strtok(list, ","); 449 while(s) { 450 if (strcmp(s, type) == 0) { 451 ret = 1; 452 break; 453 } 454 s = strtok(NULL, ","); 455 } 456 return(negate ? !ret : ret); 457} 458 459 460/* Check if we should ignore this filesystem. */ 461static int ignore(struct fs_info *fs) 462{ 463 const char *cp; 464 const char **ip; 465 int wanted = 0; 466 467 /* 468 * If the pass number is 0, ignore it. 469 */ 470 if (fs->passno == 0) 471 return 1; 472 473 /* 474 * If a specific fstype is specified, and it doesn't match, 475 * ignore it. 476 */ 477 if (!fs_match(fs->type, fstype)) return 1; 478 479 /* Are we ignoring this type? */ 480 for(ip = ignored_types; *ip; ip++) 481 if (strcmp(fs->type, *ip) == 0) return(1); 482 483 /* Do we really really want to check this fs? */ 484 for(ip = really_wanted; *ip; ip++) 485 if (strcmp(fs->type, *ip) == 0) { 486 wanted = 1; 487 break; 488 } 489 490 /* See if the <fsck.fs> program is available. */ 491 if (find_fsck(fs->type) == NULL) { 492 if (wanted) 493 fprintf(stderr, "fsck: cannot check %s: fsck.%s not found\n", 494 fs->device, fs->type); 495 return(1); 496 } 497 498 /* We can and want to check this file system type. */ 499 return 0; 500} 501 502/* 503 * Return the "base device" given a particular device; this is used to 504 * assure that we only fsck one partition on a particular drive at any 505 * one time. Otherwise, the disk heads will be seeking all over the 506 * place. 507 */ 508static const char *base_device(char *device) 509{ 510 const char **base; 511 512 for (base = base_devices; *base; base++) { 513 if (!strncmp(*base, device, strlen(*base))) 514 return *base; 515 } 516 return device; 517} 518 519/* 520 * Returns TRUE if a partition on the same disk is already being 521 * checked. 522 */ 523static int device_already_active(char *device) 524{ 525 struct fsck_instance *inst; 526 const char *base; 527 528 base = base_device(device); 529 530 for (inst = instance_list; inst; inst = inst->next) { 531 if (!strcmp(base, base_device(inst->device))) 532 return 1; 533 } 534 535 return 0; 536} 537 538/* Check all file systems, using the /etc/fstab table. */ 539static int check_all(NOARGS) 540{ 541 struct fs_info *fs = NULL; 542 struct fsck_instance *inst; 543 int status = EXIT_OK; 544 int not_done_yet = 1; 545 int passno = 0; 546 int pass_done; 547 548 if (verbose) 549 printf("Checking all file systems.\n"); 550 551 /* 552 * Find and check the root filesystem first. 553 */ 554 if (!parallel_root) { 555 for (fs = filesys_info; fs; fs = fs->next) { 556 if (!strcmp(fs->mountpt, "/")) 557 break; 558 } 559 if (fs && !skip_root && !ignore(fs)) { 560 fsck_device(fs->device); 561 fs->flags |= FLAG_DONE; 562 status |= wait_all(); 563 if (status > EXIT_NONDESTRUCT) 564 return status; 565 } 566 } 567 if (fs) fs->flags |= FLAG_DONE; 568 569 /* 570 * Mark filesystems that should be ignored as done. 571 */ 572 for (fs = filesys_info; fs; fs = fs->next) { 573 if (ignore(fs)) 574 fs->flags |= FLAG_DONE; 575 } 576 577 while (not_done_yet) { 578 not_done_yet = 0; 579 pass_done = 1; 580 581 for (fs = filesys_info; fs; fs = fs->next) { 582 if (fs->flags & FLAG_DONE) 583 continue; 584 /* 585 * If the filesystem's pass number is higher 586 * than the current pass number, then we don't 587 * do it yet. 588 */ 589 if (fs->passno > passno) { 590 not_done_yet++; 591 continue; 592 } 593 /* 594 * If a filesystem on a particular device has 595 * already been spawned, then we need to defer 596 * this to another pass. 597 */ 598 if (device_already_active(fs->device)) { 599 pass_done = 0; 600 continue; 601 } 602 /* 603 * Spawn off the fsck process 604 */ 605 fsck_device(fs->device); 606 fs->flags |= FLAG_DONE; 607 608 if (serialize) { 609 pass_done = 0; 610 break; /* Only do one filesystem at a time */ 611 612 } 613 } 614 inst = wait_one(); 615 if (inst) { 616 status |= inst->exit_status; 617 free_instance(inst); 618 } 619 if (pass_done) { 620 status |= wait_all(); 621 if (verbose) 622 printf("----------------------------------\n"); 623 passno++; 624 } else 625 not_done_yet++; 626 } 627 status |= wait_all(); 628 return status; 629} 630 631static void usage(NOARGS) 632{ 633 fprintf(stderr, 634 "Usage: fsck [-AV] [-t fstype] [fs-options] filesys\n"); 635 exit(EXIT_USAGE); 636} 637 638static void PRS(int argc, char *argv[]) 639{ 640 int i, j; 641 char *arg; 642 char options[128]; 643 int opt = 0; 644 int opts_for_fsck = 0; 645 646 num_devices = 0; 647 num_args = 0; 648 instance_list = 0; 649 650 progname = argv[0]; 651 652 load_fs_info(); 653 654 for (i=1; i < argc; i++) { 655 arg = argv[i]; 656 if (!arg) 657 continue; 658 if (arg[0] == '/') { 659 if (num_devices >= MAX_DEVICES) { 660 fprintf(stderr, "%s: too many devices\n", 661 progname); 662 exit(1); 663 } 664 devices[num_devices++] = strdup(arg); 665 continue; 666 } 667 if (arg[0] != '-') { 668 if (num_args >= MAX_ARGS) { 669 fprintf(stderr, "%s: too many arguments\n", 670 progname); 671 exit(1); 672 } 673 args[num_args++] = strdup(arg); 674 continue; 675 } 676 for (j=1; arg[j]; j++) { 677 if (opts_for_fsck) { 678 options[++opt] = arg[j]; 679 continue; 680 } 681 switch (arg[j]) { 682 case 'A': 683 doall++; 684 break; 685 case 'V': 686 verbose++; 687 break; 688 case 'N': 689 noexecute++; 690 break; 691 case 'R': 692 skip_root++; 693 break; 694 case 'T': 695 notitle++; 696 break; 697 case 'M': 698 like_mount++; 699 break; 700 case 'P': 701 parallel_root++; 702 break; 703 case 's': 704 serialize++; 705 break; 706 case 't': 707 if (arg[j+1]) { 708 fstype = strdup(arg+j+1); 709 goto next_arg; 710 } 711 if ((i+1) < argc) { 712 i++; 713 fstype = strdup(argv[i]); 714 goto next_arg; 715 } 716 usage(); 717 break; 718 case '-': 719 opts_for_fsck++; 720 break; 721 default: 722 options[++opt] = arg[j]; 723 break; 724 } 725 } 726 next_arg: 727 if (opt) { 728 options[0] = '-'; 729 options[++opt] = '\0'; 730 if (num_args >= MAX_ARGS) { 731 fprintf(stderr, 732 "%s: too many arguments\n", 733 progname); 734 exit(1); 735 } 736 args[num_args++] = strdup(options); 737 opt = 0; 738 } 739 } 740} 741 742int main(int argc, char *argv[]) 743{ 744 int i; 745 int status = 0; 746 char *oldpath = getenv("PATH"); 747 748 PRS(argc, argv); 749 750 if (!notitle) 751 printf("Parallelizing fsck version %s (%s)\n", 752 E2FSPROGS_VERSION, E2FSPROGS_DATE); 753 754 /* Update our search path to include uncommon directories. */ 755 if (oldpath) { 756 fsck_path = malloc (strlen (fsck_prefix_path) + 1 + 757 strlen (oldpath) + 1); 758 strcpy (fsck_path, fsck_prefix_path); 759 strcat (fsck_path, ":"); 760 strcat (fsck_path, oldpath); 761 } else { 762 fsck_path = strdup(fsck_prefix_path); 763 } 764 765 /* If -A was specified ("check all"), do that! */ 766 if (doall) 767 return check_all(); 768 769 for (i = 0 ; i < num_devices; i++) { 770 fsck_device(devices[i]); 771 if (serialize) { 772 struct fsck_instance *inst; 773 774 inst = wait_one(); 775 if (inst) { 776 status |= inst->exit_status; 777 free_instance(inst); 778 } 779 } 780 } 781 status |= wait_all(); 782 free(fsck_path); 783 return status; 784} 785