fsck.c revision d4cf2fcda2aee14d1e312d8e145dd54f480ffeae
1/*
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 *
11 * Usage:	fsck [-ACVRNTM] [-s] [-t fstype] [fs-options] device
12 *
13 * 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 *
21 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 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%
27 */
28
29#include <sys/types.h>
30#include <sys/wait.h>
31#include <sys/signal.h>
32#include <sys/stat.h>
33#include <limits.h>
34#include <stdio.h>
35#include <ctype.h>
36#include <string.h>
37#include <time.h>
38#if HAVE_STDLIB_H
39#include <stdlib.h>
40#endif
41#if HAVE_ERRNO_H
42#include <errno.h>
43#endif
44#if HAVE_PATHS_H
45#include <paths.h>
46#endif
47#if HAVE_UNISTD_H
48#include <unistd.h>
49#endif
50#if HAVE_ERRNO_H
51#include <errno.h>
52#endif
53#include <malloc.h>
54
55#include "../version.h"
56#include "nls-enable.h"
57#include "fsck.h"
58#include "get_device_by_label.h"
59
60#ifndef _PATH_MNTTAB
61#define	_PATH_MNTTAB	"/etc/fstab"
62#endif
63
64static const char *ignored_types[] = {
65	"ignore",
66	"iso9660",
67	"nfs",
68	"proc",
69	"sw",
70	"swap",
71	NULL
72};
73
74static const char *really_wanted[] = {
75	"minix",
76	"ext2",
77	"ext3",
78	"xiafs",
79	NULL
80};
81
82#define BASE_MD "/dev/md"
83
84/*
85 * Global variables for options
86 */
87char *devices[MAX_DEVICES];
88char *args[MAX_ARGS];
89int num_devices, num_args;
90
91int verbose = 0;
92int doall = 0;
93int noexecute = 0;
94int serialize = 0;
95int skip_root = 0;
96int like_mount = 0;
97int notitle = 0;
98int parallel_root = 0;
99int progress = 0;
100int force_all_parallel = 0;
101char *progname;
102char *fstype = NULL;
103struct fs_info *filesys_info;
104struct fsck_instance *instance_list;
105const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc";
106char *fsck_path = 0;
107static int ignore(struct fs_info *);
108
109static char *string_copy(const char *s)
110{
111	char	*ret;
112
113	ret = malloc(strlen(s)+1);
114	if (ret)
115		strcpy(ret, s);
116	return ret;
117}
118
119static char *skip_over_blank(char *cp)
120{
121	while (*cp && isspace(*cp))
122		cp++;
123	return cp;
124}
125
126static char *skip_over_word(char *cp)
127{
128	while (*cp && !isspace(*cp))
129		cp++;
130	return cp;
131}
132
133static void strip_line(char *line)
134{
135	char	*p;
136
137	while (*line) {
138		p = line + strlen(line) - 1;
139		if ((*p == '\n') || (*p == '\r'))
140			*p = 0;
141		else
142			break;
143	}
144}
145
146static char *parse_word(char **buf)
147{
148	char *word, *next;
149
150	word = *buf;
151	if (*word == 0)
152		return 0;
153
154	word = skip_over_blank(word);
155	next = skip_over_word(word);
156	if (*next)
157		*next++ = 0;
158	*buf = next;
159	return word;
160}
161
162static void free_instance(struct fsck_instance *i)
163{
164	if (i->prog)
165		free(i->prog);
166	if (i->device)
167		free(i->device);
168	if (i->base_device)
169		free(i->base_device);
170	free(i);
171	return;
172}
173
174static int parse_fstab_line(char *line, struct fs_info **ret_fs)
175{
176	char	*device, *mntpnt, *type, *opts, *freq, *passno, *cp;
177	struct fs_info *fs;
178
179	*ret_fs = 0;
180	strip_line(line);
181	if ((cp = strchr(line, '#')))
182		*cp = 0;	/* Ignore everything after the comment char */
183	cp = line;
184
185	device = parse_word(&cp);
186	mntpnt = parse_word(&cp);
187	type = parse_word(&cp);
188	opts = parse_word(&cp);
189	freq = parse_word(&cp);
190	passno = parse_word(&cp);
191
192	if (!device)
193		return 0;	/* Allow blank lines */
194
195	if (!mntpnt || !type)
196		return -1;
197
198	if (!(fs = malloc(sizeof(struct fs_info))))
199		return -1;
200
201	fs->device = string_copy(device);
202	fs->mountpt = string_copy(mntpnt);
203	fs->type = string_copy(type);
204	fs->opts = string_copy(opts ? opts : "");
205	fs->freq = freq ? atoi(freq) : -1;
206	fs->passno = passno ? atoi(passno) : -1;
207	fs->flags = 0;
208	fs->next = NULL;
209
210	*ret_fs = fs;
211
212	return 0;
213}
214
215/*
216 * Interpret the device name if necessary
217 */
218static char *interpret_device(char *spec)
219{
220	char *dev = NULL;
221
222	if (!strncmp(spec, "UUID=", 5))
223		dev = get_spec_by_uuid(spec+5);
224	else if (!strncmp(spec, "LABEL=", 6))
225		dev = get_spec_by_volume_label(spec+6);
226	else
227		return spec;
228	if (dev) {
229		free(spec);
230		return (dev);
231	}
232	/*
233	 * Check to see if this was because /proc/partitions isn't
234	 * found.
235	 */
236	if (access("/proc/partitions", R_OK) < 0) {
237		fprintf(stderr, "Couldn't open /proc/partitions: %s\n",
238			strerror(errno));
239		fprintf(stderr, "Is /proc mounted?\n");
240		exit(1);
241	}
242	/*
243	 * Check to see if this is because we're not running as root
244	 */
245	if (geteuid())
246		fprintf(stderr, "Must be root to scan for matching "
247			"filesystems: %s\n", spec);
248	else
249		fprintf(stderr, "Couldn't find matching filesystem: %s\n",
250			spec);
251	exit(1);
252}
253
254/*
255 * Load the filesystem database from /etc/fstab
256 */
257static void load_fs_info(const char *filename)
258{
259	FILE	*f;
260	char	buf[1024];
261	int	lineno = 0;
262	int	old_fstab = 1;
263	struct fs_info *fs, *fs_last = NULL;
264
265	filesys_info = NULL;
266	if ((f = fopen(filename, "r")) == NULL) {
267		fprintf(stderr, _("WARNING: couldn't open %s: %s\n"),
268			filename, strerror(errno));
269		return;
270	}
271	while (!feof(f)) {
272		lineno++;
273		if (!fgets(buf, sizeof(buf), f))
274			break;
275		buf[sizeof(buf)-1] = 0;
276		if (parse_fstab_line(buf, &fs) < 0) {
277			fprintf(stderr, _("WARNING: bad format "
278				"on line %d of %s\n"), lineno, filename);
279			continue;
280		}
281		if (!fs)
282			continue;
283		if (!filesys_info)
284			filesys_info = fs;
285		else
286			fs_last->next = fs;
287		fs_last = fs;
288		if (fs->passno < 0)
289			fs->passno = 0;
290		else
291			old_fstab = 0;
292	}
293
294	fclose(f);
295
296	if (old_fstab) {
297		fprintf(stderr, _("\007\007\007"
298		"WARNING: Your /etc/fstab does not contain the fsck passno\n"
299		"	field.  I will kludge around things for you, but you\n"
300		"	should fix your /etc/fstab file as soon as you can.\n\n"));
301
302		for (fs = filesys_info; fs; fs = fs->next) {
303			fs->passno = 1;
304		}
305	}
306}
307
308/* Lookup filesys in /etc/fstab and return the corresponding entry. */
309static struct fs_info *lookup(char *filesys)
310{
311	struct fs_info *fs;
312	int	try_again = 0;
313
314	/* No filesys name given. */
315	if (filesys == NULL)
316		return NULL;
317
318	for (fs = filesys_info; fs; fs = fs->next) {
319		if (strchr(fs->device, '='))
320			try_again++;
321		if (!strcmp(filesys, fs->device) ||
322		    !strcmp(filesys, fs->mountpt))
323			break;
324	}
325	if (fs && strchr(fs->device, '='))
326		fs->device = interpret_device(fs->device);
327
328	if (fs || !try_again)
329		return fs;
330
331	for (fs = filesys_info; fs; fs = fs->next) {
332		fs->device = interpret_device(fs->device);
333		if (!strcmp(filesys, fs->device) ||
334		    !strcmp(filesys, fs->mountpt))
335			break;
336	}
337
338	return fs;
339}
340
341/* Find fsck program for a given fs type. */
342static char *find_fsck(char *type)
343{
344  char *s;
345  const char *tpl;
346  static char prog[256];
347  char *p = string_copy(fsck_path);
348  struct stat st;
349
350  /* Are we looking for a program or just a type? */
351  tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
352
353  for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
354	sprintf(prog, tpl, s, type);
355	if (stat(prog, &st) == 0) break;
356  }
357  free(p);
358  return(s ? prog : NULL);
359}
360
361static int progress_active(NOARGS)
362{
363	struct fsck_instance *inst;
364
365	for (inst = instance_list; inst; inst = inst->next) {
366		if (inst->flags & FLAG_DONE)
367			continue;
368		if (inst->flags & FLAG_PROGRESS)
369			return 1;
370	}
371	return 0;
372}
373
374/*
375 * Execute a particular fsck program, and link it into the list of
376 * child processes we are waiting for.
377 */
378static int execute(const char *type, char *device, char *mntpt,
379		   int interactive)
380{
381	char *s, *argv[80], prog[80];
382	int  argc, i;
383	struct fsck_instance *inst, *p;
384	pid_t	pid;
385
386	inst = malloc(sizeof(struct fsck_instance));
387	if (!inst)
388		return ENOMEM;
389	memset(inst, 0, sizeof(struct fsck_instance));
390
391	sprintf(prog, "fsck.%s", type);
392	argv[0] = string_copy(prog);
393	argc = 1;
394
395	for (i=0; i <num_args; i++)
396		argv[argc++] = string_copy(args[i]);
397
398	if (progress & !progress_active()) {
399		if ((strcmp(type, "ext2") == 0) ||
400		    (strcmp(type, "ext3") == 0)) {
401			argv[argc++] = string_copy("-C0");
402			inst->flags |= FLAG_PROGRESS;
403		}
404	}
405
406	argv[argc++] = string_copy(device);
407	argv[argc] = 0;
408
409	s = find_fsck(prog);
410	if (s == NULL) {
411		fprintf(stderr, _("fsck: %s: not found\n"), prog);
412		return ENOENT;
413	}
414
415	if (verbose || noexecute) {
416		printf("[%s -- %s] ", s, mntpt ? mntpt : device);
417		for (i=0; i < argc; i++)
418			printf("%s ", argv[i]);
419		printf("\n");
420	}
421
422	/* Fork and execute the correct program. */
423	if (noexecute)
424		pid = -1;
425	else if ((pid = fork()) < 0) {
426		perror("fork");
427		return errno;
428	} else if (pid == 0) {
429		if (!interactive)
430			close(0);
431		(void) execv(s, argv);
432		perror(argv[0]);
433		exit(EXIT_ERROR);
434	}
435
436	for (i=0; i < argc; i++)
437		free(argv[i]);
438
439	inst->pid = pid;
440	inst->prog = string_copy(prog);
441	inst->type = string_copy(type);
442	inst->device = string_copy(device);
443	inst->base_device = base_device(device);
444	inst->start_time = time(0);
445	inst->next = NULL;
446
447	/*
448	 * Find the end of the list, so we add the instance on at the end.
449	 */
450	for (p = instance_list; p && p->next; p = p->next);
451
452	if (p)
453		p->next = inst;
454	else
455		instance_list = inst;
456
457	return 0;
458}
459
460/*
461 * Wait for one child process to exit; when it does, unlink it from
462 * the list of executing child processes, and return it.
463 */
464static struct fsck_instance *wait_one(NOARGS)
465{
466	int	status;
467	int	sig;
468	struct fsck_instance *inst, *inst2, *prev;
469	pid_t	pid;
470
471	if (!instance_list)
472		return NULL;
473
474	if (noexecute) {
475		inst = instance_list;
476		instance_list = inst->next;
477		inst->exit_status = 0;
478		return(inst);
479	}
480
481	/*
482	 * gcc -Wall fails saving throw against stupidity
483	 * (inst and prev are thought to be uninitialized variables)
484	 */
485	inst = prev = NULL;
486
487	do {
488		pid = wait(&status);
489		if (pid < 0) {
490			if ((errno == EINTR) || (errno == EAGAIN))
491				continue;
492			if (errno == ECHILD) {
493				fprintf(stderr,
494					_("%s: wait: No more child process?!?\n"),
495					progname);
496				return NULL;
497			}
498			perror("wait");
499			continue;
500		}
501		for (prev = 0, inst = instance_list;
502		     inst;
503		     prev = inst, inst = inst->next) {
504			if (inst->pid == pid)
505				break;
506		}
507	} while (!inst);
508
509	if (WIFEXITED(status))
510		status = WEXITSTATUS(status);
511	else if (WIFSIGNALED(status)) {
512		sig = WTERMSIG(status);
513		if (sig == SIGINT) {
514			status = EXIT_UNCORRECTED;
515		} else {
516			printf(_("Warning... %s for device %s exited "
517			       "with signal %d.\n"),
518			       inst->prog, inst->device, sig);
519			status = EXIT_ERROR;
520		}
521	} else {
522		printf(_("%s %s: status is %x, should never happen.\n"),
523		       inst->prog, inst->device, status);
524		status = EXIT_ERROR;
525	}
526	inst->exit_status = status;
527	if (prev)
528		prev->next = inst->next;
529	else
530		instance_list = inst->next;
531	if (progress && (inst->flags & FLAG_PROGRESS) &&
532	    !progress_active()) {
533		for (inst2 = instance_list; inst2; inst2 = inst2->next) {
534			if (inst2->flags & FLAG_DONE)
535				continue;
536			if (strcmp(inst2->type, "ext2") &&
537			    strcmp(inst2->type, "ext3"))
538				continue;
539			/*
540			 * If we've just started the fsck, wait a tiny
541			 * bit before sending the kill, to give it
542			 * time to set up the signal handler
543			 */
544			if (inst2->start_time < time(0)+2) {
545				if (fork() == 0) {
546					sleep(1);
547					kill(inst2->pid, SIGUSR1);
548					exit(0);
549				}
550			} else
551				kill(inst2->pid, SIGUSR1);
552			inst2->flags |= FLAG_PROGRESS;
553			break;
554		}
555	}
556	return inst;
557}
558
559/*
560 * Wait until all executing child processes have exited; return the
561 * logical OR of all of their exit code values.
562 */
563static int wait_all(NOARGS)
564{
565	struct fsck_instance *inst;
566	int	global_status = 0;
567
568	while (instance_list) {
569		inst = wait_one();
570		if (!inst)
571			break;
572		global_status |= inst->exit_status;
573		free_instance(inst);
574	}
575	return global_status;
576}
577
578/*
579 * Run the fsck program on a particular device
580 *
581 * If the type is specified using -t, and it isn't prefixed with "no"
582 * (as in "noext2") and only one filesystem type is specified, then
583 * use that type regardless of what is specified in /etc/fstab.
584 *
585 * If the type isn't specified by the user, then use either the type
586 * specified in /etc/fstab, or DEFAULT_FSTYPE.
587 */
588static void fsck_device(char *device, int interactive)
589{
590	const char *type = 0;
591	struct fs_info *fsent;
592	int retval;
593
594	if (fstype && strncmp(fstype, "no", 2) && !strchr(fstype, ','))
595		type = fstype;
596
597	if ((fsent = lookup(device))) {
598		device = fsent->device;
599		if (!type)
600			type = fsent->type;
601	}
602	if (!type)
603		type = DEFAULT_FSTYPE;
604
605	retval = execute(type, device, fsent ? fsent->mountpt : 0,
606			 interactive);
607	if (retval) {
608		fprintf(stderr, _("%s: Error %d while executing fsck.%s "
609			"for %s\n"), progname, retval, type, device);
610	}
611}
612
613/* See if filesystem type matches the list. */
614static int fs_match(char *type, char *fs_type)
615{
616  int ret = 0, negate = 0;
617  char list[128];
618  char *s;
619
620  if (!fs_type) return(1);
621
622  if (strncmp(fs_type, "no", 2) == 0) {
623	fs_type += 2;
624	negate = 1;
625  }
626  strcpy(list, fs_type);
627  s = strtok(list, ",");
628  while(s) {
629	if (strcmp(s, type) == 0) {
630		ret = 1;
631		break;
632	}
633	s = strtok(NULL, ",");
634  }
635  return(negate ? !ret : ret);
636}
637
638
639/* Check if we should ignore this filesystem. */
640static int ignore(struct fs_info *fs)
641{
642	const char **ip;
643	int wanted = 0;
644
645	/*
646	 * If the pass number is 0, ignore it.
647	 */
648	if (fs->passno == 0)
649		return 1;
650
651	/*
652	 * If a specific fstype is specified, and it doesn't match,
653	 * ignore it.
654	 */
655	if (!fs_match(fs->type, fstype)) return 1;
656
657	/* Are we ignoring this type? */
658	for(ip = ignored_types; *ip; ip++)
659		if (strcmp(fs->type, *ip) == 0) return 1;
660
661	/* Do we really really want to check this fs? */
662	for(ip = really_wanted; *ip; ip++)
663		if (strcmp(fs->type, *ip) == 0) {
664			wanted = 1;
665			break;
666		}
667
668	/* See if the <fsck.fs> program is available. */
669	if (find_fsck(fs->type) == NULL) {
670		if (wanted)
671			fprintf(stderr, _("fsck: cannot check %s: fsck.%s not found\n"),
672				fs->device, fs->type);
673		return 1;
674	}
675
676	/* We can and want to check this file system type. */
677	return 0;
678}
679
680/*
681 * Returns TRUE if a partition on the same disk is already being
682 * checked.
683 */
684static int device_already_active(char *device)
685{
686	struct fsck_instance *inst;
687	char *base;
688
689	if (force_all_parallel)
690		return 0;
691
692#ifdef BASE_MD
693	/* Don't check a soft raid disk with any other disk */
694	if (instance_list &&
695	    (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) ||
696	     !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)))
697		return 1;
698#endif
699
700	base = base_device(device);
701	if (!base)
702		return 0;
703	for (inst = instance_list; inst; inst = inst->next) {
704		if (!strcmp(base, inst->base_device)) {
705			free(base);
706			return 1;
707		}
708	}
709	free(base);
710	return 0;
711}
712
713/* Check all file systems, using the /etc/fstab table. */
714static int check_all(NOARGS)
715{
716	struct fs_info *fs = NULL;
717	struct fsck_instance *inst;
718	int status = EXIT_OK;
719	int not_done_yet = 1;
720	int passno = 1;
721	int pass_done;
722
723	if (verbose)
724		printf(_("Checking all file systems.\n"));
725
726	/*
727	 * Do an initial scan over the filesystem; mark filesystems
728	 * which should be ignored as done, and resolve LABEL= and
729	 * UUID= specifications to the real device.
730	 */
731	for (fs = filesys_info; fs; fs = fs->next) {
732		if (ignore(fs))
733			fs->flags |= FLAG_DONE;
734		fs->device = interpret_device(fs->device);
735	}
736
737	/*
738	 * Find and check the root filesystem.
739	 */
740	if (!parallel_root) {
741		for (fs = filesys_info; fs; fs = fs->next) {
742			if (!strcmp(fs->mountpt, "/"))
743				break;
744		}
745		if (fs) {
746			if (!skip_root && !ignore(fs)) {
747				fsck_device(fs->device, 1);
748				status |= wait_all();
749				if (status > EXIT_NONDESTRUCT)
750					return status;
751			}
752			fs->flags |= FLAG_DONE;
753		}
754	}
755
756	while (not_done_yet) {
757		not_done_yet = 0;
758		pass_done = 1;
759
760		for (fs = filesys_info; fs; fs = fs->next) {
761			if (fs->flags & FLAG_DONE)
762				continue;
763			/*
764			 * If the filesystem's pass number is higher
765			 * than the current pass number, then we don't
766			 * do it yet.
767			 */
768			if (fs->passno > passno) {
769				not_done_yet++;
770				continue;
771			}
772			/*
773			 * If a filesystem on a particular device has
774			 * already been spawned, then we need to defer
775			 * this to another pass.
776			 */
777			if (device_already_active(fs->device)) {
778				pass_done = 0;
779				continue;
780			}
781			/*
782			 * Spawn off the fsck process
783			 */
784			fsck_device(fs->device, serialize);
785			fs->flags |= FLAG_DONE;
786
787			if (serialize) {
788				pass_done = 0;
789				break; /* Only do one filesystem at a time */
790			}
791		}
792		if (verbose > 1)
793			printf(_("--waiting-- (pass %d)\n"), passno);
794		inst = wait_one();
795		if (inst) {
796			status |= inst->exit_status;
797			free_instance(inst);
798		}
799		if (pass_done) {
800			status |= wait_all();
801			if (verbose > 1)
802				printf("----------------------------------\n");
803			passno++;
804		} else
805			not_done_yet++;
806	}
807	status |= wait_all();
808	return status;
809}
810
811static void usage(NOARGS)
812{
813	fprintf(stderr,
814		_("Usage: fsck [-ACNPRTV] [-t fstype] [fs-options] filesys\n"));
815	exit(EXIT_USAGE);
816}
817
818static void PRS(int argc, char *argv[])
819{
820	int	i, j;
821	char	*arg;
822	char	options[128];
823	int	opt = 0;
824	int     opts_for_fsck = 0;
825
826	num_devices = 0;
827	num_args = 0;
828	instance_list = 0;
829
830	progname = argv[0];
831
832	for (i=1; i < argc; i++) {
833		arg = argv[i];
834		if (!arg)
835			continue;
836		if ((arg[0] == '/' && !opts_for_fsck) ||
837		    (strncmp(arg, "LABEL=", 6) == 0) ||
838		    (strncmp(arg, "UUID=", 5) == 0)) {
839			if (num_devices >= MAX_DEVICES) {
840				fprintf(stderr, _("%s: too many devices\n"),
841					progname);
842				exit(1);
843			}
844			devices[num_devices++] =
845				interpret_device(string_copy(arg));
846			continue;
847		}
848		if (arg[0] != '-' || opts_for_fsck) {
849			if (num_args >= MAX_ARGS) {
850				fprintf(stderr, _("%s: too many arguments\n"),
851					progname);
852				exit(1);
853			}
854			args[num_args++] = string_copy(arg);
855			continue;
856		}
857		for (j=1; arg[j]; j++) {
858			if (opts_for_fsck) {
859				options[++opt] = arg[j];
860				continue;
861			}
862			switch (arg[j]) {
863			case 'A':
864				doall++;
865				break;
866			case 'C':
867				progress++;
868				break;
869			case 'V':
870				verbose++;
871				break;
872			case 'N':
873				noexecute++;
874				break;
875			case 'R':
876				skip_root++;
877				break;
878			case 'T':
879				notitle++;
880				break;
881			case 'M':
882				like_mount++;
883				break;
884			case 'P':
885				parallel_root++;
886				break;
887			case 's':
888				serialize++;
889				break;
890			case 't':
891				if (arg[j+1]) {
892					fstype = string_copy(arg+j+1);
893					goto next_arg;
894				}
895				if ((i+1) < argc) {
896					i++;
897					fstype = string_copy(argv[i]);
898					goto next_arg;
899				}
900				usage();
901				break;
902			case '-':
903				opts_for_fsck++;
904				break;
905			default:
906				options[++opt] = arg[j];
907				break;
908			}
909		}
910	next_arg:
911		if (opt) {
912			options[0] = '-';
913			options[++opt] = '\0';
914			if (num_args >= MAX_ARGS) {
915				fprintf(stderr,
916					_("%s: too many arguments\n"),
917					progname);
918				exit(1);
919			}
920			args[num_args++] = string_copy(options);
921			opt = 0;
922		}
923	}
924	if (getenv("FSCK_FORCE_ALL_PARALLEL"))
925		force_all_parallel++;
926}
927
928int main(int argc, char *argv[])
929{
930	int i;
931	int status = 0;
932	int interactive = 0;
933	char *oldpath = getenv("PATH");
934	const char *fstab;
935
936#ifdef ENABLE_NLS
937	setlocale(LC_MESSAGES, "");
938	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
939	textdomain(NLS_CAT_NAME);
940#endif
941	PRS(argc, argv);
942
943	if (!notitle)
944		printf(_("Parallelizing fsck version %s (%s)\n"),
945			E2FSPROGS_VERSION, E2FSPROGS_DATE);
946
947	fstab = getenv("FSTAB_FILE");
948	if (!fstab)
949		fstab = _PATH_MNTTAB;
950	load_fs_info(fstab);
951
952	/* Update our search path to include uncommon directories. */
953	if (oldpath) {
954		fsck_path = malloc (strlen (fsck_prefix_path) + 1 +
955				    strlen (oldpath) + 1);
956		strcpy (fsck_path, fsck_prefix_path);
957		strcat (fsck_path, ":");
958		strcat (fsck_path, oldpath);
959	} else {
960		fsck_path = string_copy(fsck_prefix_path);
961	}
962
963	if ((num_devices == 1) || (serialize))
964		interactive = 1;
965
966	/* If -A was specified ("check all"), do that! */
967	if (doall)
968		return check_all();
969
970	for (i = 0 ; i < num_devices; i++) {
971		fsck_device(devices[i], interactive);
972		if (serialize) {
973			struct fsck_instance *inst;
974
975			inst = wait_one();
976			if (inst) {
977				status |= inst->exit_status;
978				free_instance(inst);
979			}
980		}
981	}
982	status |= wait_all();
983	free(fsck_path);
984	return status;
985}
986