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