blob: 29c87413040acad9ff0dcd0f14fbc6e1b719623d [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * pfsck --- A generic, parallelizing front-end for the fsck program.
3 * It will automatically try to run fsck programs in parallel if the
4 * devices are on separate spindles. It is based on the same ideas as
5 * the generic front end for fsck by David Engel and Fred van Kempen,
6 * but it has been completely rewritten from scratch to support
7 * parallel execution.
8 *
9 * Written by Theodore Ts'o, <tytso@mit.edu>
10 *
Theodore Ts'of3db3561997-04-26 13:34:30 +000011 * Usage: fsck [-AVRNTM] [-s] [-t fstype] [fs-options] device
Theodore Ts'o3839e651997-04-26 13:21:57 +000012 *
Theodore Ts'of3db3561997-04-26 13:34:30 +000013 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
14 * o Changed -t fstype to behave like with mount when -A (all file
15 * systems) or -M (like mount) is specified.
16 * o fsck looks if it can find the fsck.type program to decide
17 * if it should ignore the fs type. This way more fsck programs
18 * can be added without changing this front-end.
19 * o -R flag skip root file system.
20 *
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000021 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
22 *
23 * %Begin-Header%
24 * This file may be redistributed under the terms of the GNU Public
25 * License.
26 * %End-Header%
Theodore Ts'o3839e651997-04-26 13:21:57 +000027 */
28
29#include <sys/types.h>
30#include <sys/wait.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000031#include <sys/signal.h>
32#include <sys/stat.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000033#include <limits.h>
34#include <stdio.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000035#include <string.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000036#if HAVE_STDLIB_H
37#include <stdlib.h>
38#endif
39#if HAVE_ERRNO_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000040#include <errno.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000041#endif
42#if HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000043#include <mntent.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000044#endif
45#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000046#include <unistd.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000047#endif
48#if HAVE_ERRNO_H
49#include <errno.h>
50#endif
51#include <malloc.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000052
53#include "../version.h"
54#include "fsck.h"
55
56static const char *ignored_types[] = {
57 "ignore",
58 "iso9660",
Theodore Ts'o3839e651997-04-26 13:21:57 +000059 "nfs",
60 "proc",
61 "sw",
62 "swap",
63 NULL
64};
65
Theodore Ts'of3db3561997-04-26 13:34:30 +000066static const char *really_wanted[] = {
67 "minix",
68 "ext2",
69 "xiafs",
70 NULL
71};
72
73#ifdef DEV_DSK_DEVICES
74static const char *base_devices[] = {
75 "/dev/dsk/hda",
76 "/dev/dsk/hdb",
77 "/dev/dsk/hdc",
78 "/dev/dsk/hdd",
79 "/dev/dsk/hd1a",
80 "/dev/dsk/hd1b",
81 "/dev/dsk/hd1c",
82 "/dev/dsk/hd1d",
83 "/dev/dsk/sda",
84 "/dev/dsk/sdb",
85 "/dev/dsk/sdc",
86 "/dev/dsk/sdd",
87 "/dev/dsk/sde",
88 "/dev/dsk/sdf",
89 "/dev/dsk/sdg",
90 NULL
91};
92#else
Theodore Ts'o3839e651997-04-26 13:21:57 +000093static const char *base_devices[] = {
94 "/dev/hda",
95 "/dev/hdb",
96 "/dev/hdc",
97 "/dev/hdd",
Theodore Ts'of3db3561997-04-26 13:34:30 +000098 "/dev/hd1a",
99 "/dev/hd1b",
100 "/dev/hd1c",
101 "/dev/hd1d",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102 "/dev/sda",
103 "/dev/sdb",
104 "/dev/sdc",
105 "/dev/sdd",
106 "/dev/sde",
107 "/dev/sdf",
108 "/dev/sdg",
109 NULL
110};
Theodore Ts'of3db3561997-04-26 13:34:30 +0000111#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000112
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;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000124int skip_root = 0;
125int like_mount = 0;
126int notitle = 0;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000127int parallel_root = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000128char *progname;
129char *fstype = NULL;
130struct fs_info *filesys_info;
131struct fsck_instance *instance_list;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000132const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc";
133char *fsck_path = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000134static int ignore(struct fs_info *);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000135
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000136#ifdef HAVE_STRDUP
137#ifdef _POSIX_SOURCE
138extern char *strdup(const char *s);
139#endif
140#else
Theodore Ts'of3db3561997-04-26 13:34:30 +0000141static char *strdup(const char *s)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000142{
143 char *ret;
144
145 ret = malloc(strlen(s)+1);
146 if (ret)
147 strcpy(ret, s);
148 return ret;
149}
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000150#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000151
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{
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000167#if HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +0000168 FILE *mntfile;
169 struct mntent *mp;
170 struct fs_info *fs;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000171 struct fs_info *fs_last = NULL;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000172 int old_fstab = 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000173
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;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000191 fs->next = NULL;
192 if (!filesys_info)
193 filesys_info = fs;
194 else
195 fs_last->next = fs;
196 fs_last = fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000197 if (fs->passno)
198 old_fstab = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000199 }
200
201 (void) endmntent(mntfile);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000202
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 }
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000215#else
216 filesys_info = NULL;
217#endif /* HAVE_MNTENT_H */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000218}
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
Theodore Ts'of3db3561997-04-26 13:34:30 +0000238/* 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
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258/*
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{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000264 char *s, *argv[80];
Theodore Ts'o3839e651997-04-26 13:21:57 +0000265 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
Theodore Ts'of3db3561997-04-26 13:34:30 +0000278 s = find_fsck(prog);
279 if (s == NULL) {
280 fprintf(stderr, "fsck: %s: not found\n", prog);
281 return ENOENT;
282 }
283
Theodore Ts'o3839e651997-04-26 13:21:57 +0000284 if (verbose || noexecute) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000285 printf("[%s] ", s);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000286 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) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000298 (void) execv(s, argv);
299 perror(argv[0]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000300 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;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000322 int sig;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000323 struct fsck_instance *inst, *prev;
324 pid_t pid;
325
326 if (!instance_list)
327 return NULL;
328
329retry:
330 pid = wait(&status);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000331 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 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000354 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 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000371 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
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000400 *
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.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000407 */
408static void fsck_device(char *device)
409{
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000410 const char *type = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000411 struct fs_info *fsent;
412 int retval;
413 char prog[80];
414
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000415 if (fstype && strncmp(fstype, "no", 2) && !strchr(fstype, ','))
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000416 type = fstype;
417
Theodore Ts'of3db3561997-04-26 13:34:30 +0000418 if ((fsent = lookup(device))) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000419 device = fsent->device;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000420 if (!type)
421 type = fsent->type;
422 }
423 if (!type)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000424 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
Theodore Ts'of3db3561997-04-26 13:34:30 +0000434/* 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
Theodore Ts'o3839e651997-04-26 13:21:57 +0000460/* Check if we should ignore this filesystem. */
461static int ignore(struct fs_info *fs)
462{
463 const char *cp;
464 const char **ip;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000465 int wanted = 0;
466
467 /*
468 * If the pass number is 0, ignore it.
469 */
470 if (fs->passno == 0)
471 return 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000472
473 /*
474 * If a specific fstype is specified, and it doesn't match,
475 * ignore it.
476 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000477 if (!fs_match(fs->type, fstype)) return 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000478
Theodore Ts'of3db3561997-04-26 13:34:30 +0000479 /* 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. */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000499 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;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000515 }
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{
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000541 struct fs_info *fs = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000542 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 */
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000554 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 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000566 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000567 if (fs) fs->flags |= FLAG_DONE;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000568
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
Theodore Ts'o74becf31997-04-26 14:37:06 +0000608 if (serialize) {
609 pass_done = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000610 break; /* Only do one filesystem at a time */
Theodore Ts'o74becf31997-04-26 14:37:06 +0000611
612 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000613 }
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;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000691 case 'R':
692 skip_root++;
693 break;
694 case 'T':
695 notitle++;
696 break;
697 case 'M':
698 like_mount++;
699 break;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000700 case 'P':
701 parallel_root++;
702 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000703 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{
Theodore Ts'o3839e651997-04-26 13:21:57 +0000744 int i;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000745 int status = 0;
746 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000747
748 PRS(argc, argv);
749
Theodore Ts'of3db3561997-04-26 13:34:30 +0000750 if (!notitle)
751 printf("Parallelizing fsck version %s (%s)\n",
752 E2FSPROGS_VERSION, E2FSPROGS_DATE);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000753
Theodore Ts'of3db3561997-04-26 13:34:30 +0000754 /* Update our search path to include uncommon directories. */
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000755 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 {
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000762 fsck_path = strdup(fsck_prefix_path);
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000763 }
764
Theodore Ts'o3839e651997-04-26 13:21:57 +0000765 /* 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();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000775 if (inst) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000776 status |= inst->exit_status;
777 free_instance(inst);
778 }
779 }
780 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000781 status |= wait_all();
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000782 free(fsck_path);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000783 return status;
784}