1/* vi: set sw=4 ts=4: */
2/*
3 * fsck --- A generic, parallelizing front-end for the fsck program.
4 * It will automatically try to run fsck programs in parallel if the
5 * devices are on separate spindles.  It is based on the same ideas as
6 * the generic front end for fsck by David Engel and Fred van Kempen,
7 * but it has been completely rewritten from scratch to support
8 * parallel execution.
9 *
10 * Written by Theodore Ts'o, <tytso@mit.edu>
11 *
12 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
13 *   o Changed -t fstype to behave like with mount when -A (all file
14 *     systems) or -M (like mount) is specified.
15 *   o fsck looks if it can find the fsck.type program to decide
16 *     if it should ignore the fs type. This way more fsck programs
17 *     can be added without changing this front-end.
18 *   o -R flag skip root file system.
19 *
20 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
21 *      2001, 2002, 2003, 2004, 2005 by  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
30#include "libbb.h"
31
32#define EXIT_OK          0
33#define EXIT_NONDESTRUCT 1
34#define EXIT_DESTRUCT    2
35#define EXIT_UNCORRECTED 4
36#define EXIT_ERROR       8
37#define EXIT_USAGE       16
38#define FSCK_CANCELED    32     /* Aborted with a signal or ^C */
39
40/*
41 * Internal structure for mount table entries.
42 */
43
44struct fs_info {
45	struct fs_info *next;
46	char	*device;
47	char	*mountpt;
48	char	*type;
49	char	*opts;
50	int	freq;
51	int	passno;
52	int	flags;
53};
54
55#define FLAG_DONE 1
56#define FLAG_PROGRESS 2
57/*
58 * Structure to allow exit codes to be stored
59 */
60struct fsck_instance {
61	struct fsck_instance *next;
62	int	pid;
63	int	flags;
64	int	exit_status;
65	time_t	start_time;
66	char	*prog;
67	char	*type;
68	char	*device;
69	char	*base_device; /* /dev/hda for /dev/hdaN etc */
70};
71
72static const char ignored_types[] ALIGN1 =
73	"ignore\0"
74	"iso9660\0"
75	"nfs\0"
76	"proc\0"
77	"sw\0"
78	"swap\0"
79	"tmpfs\0"
80	"devpts\0";
81
82
83#define BASE_MD "/dev/md"
84
85static char **devices;
86static char **args;
87static int num_devices;
88static int num_args;
89static int verbose;
90
91#define FS_TYPE_FLAG_NORMAL 0
92#define FS_TYPE_FLAG_OPT    1
93#define FS_TYPE_FLAG_NEGOPT 2
94static char **fs_type_list;
95static uint8_t *fs_type_flag;
96static smallint fs_type_negated;
97
98static volatile smallint cancel_requested;
99static smallint doall;
100static smallint noexecute;
101static smallint serialize;
102static smallint skip_root;
103/* static smallint like_mount; */
104static smallint notitle;
105static smallint parallel_root;
106static smallint force_all_parallel;
107
108/* "progress indicator" code is somewhat buggy and ext[23] specific.
109 * We should be filesystem agnostic. IOW: there should be a well-defined
110 * API for fsck.something, NOT ad-hoc hacks in generic fsck. */
111#define DO_PROGRESS_INDICATOR 0
112#if DO_PROGRESS_INDICATOR
113static smallint progress;
114static int progress_fd;
115#endif
116
117static int num_running;
118static int max_running;
119static char *fstype;
120static struct fs_info *filesys_info;
121static struct fs_info *filesys_last;
122static struct fsck_instance *instance_list;
123
124/*
125 * Return the "base device" given a particular device; this is used to
126 * assure that we only fsck one partition on a particular drive at any
127 * one time.  Otherwise, the disk heads will be seeking all over the
128 * place.  If the base device cannot be determined, return NULL.
129 *
130 * The base_device() function returns an allocated string which must
131 * be freed.
132 */
133#if ENABLE_FEATURE_DEVFS
134/*
135 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
136 * pathames.
137 */
138static const char *const devfs_hier[] = {
139	"host", "bus", "target", "lun", NULL
140};
141#endif
142
143static char *base_device(const char *device)
144{
145	char *str, *cp;
146#if ENABLE_FEATURE_DEVFS
147	const char *const *hier;
148	const char *disk;
149	int len;
150#endif
151	cp = str = xstrdup(device);
152
153	/* Skip over /dev/; if it's not present, give up. */
154	if (strncmp(cp, "/dev/", 5) != 0)
155		goto errout;
156	cp += 5;
157
158	/*
159	 * For md devices, we treat them all as if they were all
160	 * on one disk, since we don't know how to parallelize them.
161	 */
162	if (cp[0] == 'm' && cp[1] == 'd') {
163		cp[2] = 0;
164		return str;
165	}
166
167	/* Handle DAC 960 devices */
168	if (strncmp(cp, "rd/", 3) == 0) {
169		cp += 3;
170		if (cp[0] != 'c' || !isdigit(cp[1])
171		 || cp[2] != 'd' || !isdigit(cp[3]))
172			goto errout;
173		cp[4] = 0;
174		return str;
175	}
176
177	/* Now let's handle /dev/hd* and /dev/sd* devices.... */
178	if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
179		cp += 2;
180		/* If there's a single number after /dev/hd, skip it */
181		if (isdigit(*cp))
182			cp++;
183		/* What follows must be an alpha char, or give up */
184		if (!isalpha(*cp))
185			goto errout;
186		cp[1] = 0;
187		return str;
188	}
189
190#if ENABLE_FEATURE_DEVFS
191	/* Now let's handle devfs (ugh) names */
192	len = 0;
193	if (strncmp(cp, "ide/", 4) == 0)
194		len = 4;
195	if (strncmp(cp, "scsi/", 5) == 0)
196		len = 5;
197	if (len) {
198		cp += len;
199		/*
200		 * Now we proceed down the expected devfs hierarchy.
201		 * i.e., .../host1/bus2/target3/lun4/...
202		 * If we don't find the expected token, followed by
203		 * some number of digits at each level, abort.
204		 */
205		for (hier = devfs_hier; *hier; hier++) {
206			len = strlen(*hier);
207			if (strncmp(cp, *hier, len) != 0)
208				goto errout;
209			cp += len;
210			while (*cp != '/' && *cp != 0) {
211				if (!isdigit(*cp))
212					goto errout;
213				cp++;
214			}
215			cp++;
216		}
217		cp[-1] = 0;
218		return str;
219	}
220
221	/* Now handle devfs /dev/disc or /dev/disk names */
222	disk = 0;
223	if (strncmp(cp, "discs/", 6) == 0)
224		disk = "disc";
225	else if (strncmp(cp, "disks/", 6) == 0)
226		disk = "disk";
227	if (disk) {
228		cp += 6;
229		if (strncmp(cp, disk, 4) != 0)
230			goto errout;
231		cp += 4;
232		while (*cp != '/' && *cp != 0) {
233			if (!isdigit(*cp))
234				goto errout;
235			cp++;
236		}
237		*cp = 0;
238		return str;
239	}
240#endif
241 errout:
242	free(str);
243	return NULL;
244}
245
246static void free_instance(struct fsck_instance *p)
247{
248	free(p->prog);
249	free(p->device);
250	free(p->base_device);
251	free(p);
252}
253
254static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
255					const char *type, const char *opts,
256					int freq, int passno)
257{
258	struct fs_info *fs;
259
260	fs = xzalloc(sizeof(*fs));
261	fs->device = xstrdup(device);
262	fs->mountpt = xstrdup(mntpnt);
263	fs->type = xstrdup(type);
264	fs->opts = xstrdup(opts ? opts : "");
265	fs->freq = freq;
266	fs->passno = passno;
267	/*fs->flags = 0; */
268	/*fs->next = NULL; */
269
270	if (!filesys_info)
271		filesys_info = fs;
272	else
273		filesys_last->next = fs;
274	filesys_last = fs;
275
276	return fs;
277}
278
279static void strip_line(char *line)
280{
281	char *p = line + strlen(line) - 1;
282
283	while (*line) {
284		if (*p != '\n' && *p != '\r')
285			break;
286		*p-- = '\0';
287	}
288}
289
290static char *parse_word(char **buf)
291{
292	char *word, *next;
293
294	word = *buf;
295	if (*word == '\0')
296		return NULL;
297
298	word = skip_whitespace(word);
299	next = skip_non_whitespace(word);
300	if (*next)
301		*next++ = '\0';
302	*buf = next;
303	return word;
304}
305
306static void parse_escape(char *word)
307{
308	char *q, c;
309	const char *p;
310
311	if (!word)
312		return;
313
314	for (p = q = word; *p; q++) {
315		c = *p++;
316		if (c != '\\') {
317			*q = c;
318		} else {
319			*q = bb_process_escape_sequence(&p);
320		}
321	}
322	*q = '\0';
323}
324
325static int parse_fstab_line(char *line, struct fs_info **ret_fs)
326{
327	char *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
328	struct fs_info *fs;
329
330	*ret_fs = 0;
331	strip_line(line);
332	cp = strchr(line, '#');
333	if (cp)
334		*cp = '\0'; /* Ignore everything after the comment char */
335	cp = line;
336
337	device = parse_word(&cp);
338	if (!device) return 0; /* Allow blank lines */
339	mntpnt = parse_word(&cp);
340	type = parse_word(&cp);
341	opts = parse_word(&cp);
342	freq = parse_word(&cp);
343	passno = parse_word(&cp);
344
345	if (!mntpnt || !type)
346		return -1;
347
348	parse_escape(device);
349	parse_escape(mntpnt);
350	parse_escape(type);
351	parse_escape(opts);
352	parse_escape(freq);
353	parse_escape(passno);
354
355	if (strchr(type, ','))
356		type = NULL;
357
358	fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
359			    freq ? atoi(freq) : -1,
360			    passno ? atoi(passno) : -1);
361	*ret_fs = fs;
362	return 0;
363}
364
365/* Load the filesystem database from /etc/fstab */
366static void load_fs_info(const char *filename)
367{
368	FILE *f;
369	int lineno = 0;
370	int old_fstab = 1;
371	struct fs_info *fs;
372
373	f = fopen_or_warn(filename, "r");
374	if (f == NULL) {
375		return;
376	}
377	while (1) {
378		int r;
379		char *buf = xmalloc_getline(f);
380		if (!buf) break;
381		r = parse_fstab_line(buf, &fs);
382		free(buf);
383		lineno++;
384		if (r < 0) {
385			bb_error_msg("WARNING: bad format "
386				"on line %d of %s", lineno, filename);
387			continue;
388		}
389		if (!fs)
390			continue;
391		if (fs->passno < 0)
392			fs->passno = 0;
393		else
394			old_fstab = 0;
395	}
396	fclose(f);
397
398	if (old_fstab) {
399		fputs("\007"
400"WARNING: Your /etc/fstab does not contain the fsck passno field.\n"
401"I will kludge around things for you, but you should fix\n"
402"your /etc/fstab file as soon as you can.\n\n", stderr);
403		for (fs = filesys_info; fs; fs = fs->next) {
404			fs->passno = 1;
405		}
406	}
407}
408
409/* Lookup filesys in /etc/fstab and return the corresponding entry. */
410static struct fs_info *lookup(char *filesys)
411{
412	struct fs_info *fs;
413
414	for (fs = filesys_info; fs; fs = fs->next) {
415		if (strcmp(filesys, fs->device) == 0
416		 || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
417		)
418			break;
419	}
420
421	return fs;
422}
423
424#if DO_PROGRESS_INDICATOR
425static int progress_active(void)
426{
427	struct fsck_instance *inst;
428
429	for (inst = instance_list; inst; inst = inst->next) {
430		if (inst->flags & FLAG_DONE)
431			continue;
432		if (inst->flags & FLAG_PROGRESS)
433			return 1;
434	}
435	return 0;
436}
437#endif
438
439
440/*
441 * Send a signal to all outstanding fsck child processes
442 */
443static void kill_all_if_cancel_requested(void)
444{
445	static smallint kill_sent;
446
447	struct fsck_instance *inst;
448
449	if (!cancel_requested || kill_sent)
450		return;
451
452	for (inst = instance_list; inst; inst = inst->next) {
453		if (inst->flags & FLAG_DONE)
454			continue;
455		kill(inst->pid, SIGTERM);
456	}
457	kill_sent = 1;
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(int flags)
465{
466	int status;
467	int sig;
468	struct fsck_instance *inst, *prev;
469	pid_t pid;
470
471	if (!instance_list)
472		return NULL;
473
474	if (noexecute) {
475		inst = instance_list;
476		prev = NULL;
477#ifdef RANDOM_DEBUG
478		while (inst->next && (random() & 1)) {
479			prev = inst;
480			inst = inst->next;
481		}
482#endif
483		inst->exit_status = 0;
484		goto ret_inst;
485	}
486
487	inst = prev = NULL; /* for gcc */
488	do {
489		pid = waitpid(-1, &status, flags);
490		kill_all_if_cancel_requested();
491		if (pid == 0 && (flags & WNOHANG))
492			return NULL;
493		if (pid < 0) {
494			if (errno == EINTR || errno == EAGAIN)
495				continue;
496			if (errno == ECHILD) {
497				bb_error_msg("wait: no more child process?!?");
498				return NULL;
499			}
500			bb_perror_msg("wait");
501			continue;
502		}
503		prev = NULL;
504		inst = instance_list;
505		while (inst) {
506			if (inst->pid == pid)
507				break;
508			prev = inst;
509			inst = inst->next;
510		}
511	} while (!inst);
512
513	if (WIFEXITED(status))
514		status = WEXITSTATUS(status);
515	else if (WIFSIGNALED(status)) {
516		sig = WTERMSIG(status);
517		status = EXIT_UNCORRECTED;
518		if (sig != SIGINT) {
519			printf("Warning... %s %s exited "
520				"with signal %d\n",
521				inst->prog, inst->device, sig);
522			status = EXIT_ERROR;
523		}
524	} else {
525		printf("%s %s: status is %x, should never happen\n",
526			inst->prog, inst->device, status);
527		status = EXIT_ERROR;
528	}
529	inst->exit_status = status;
530
531#if DO_PROGRESS_INDICATOR
532	if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
533		struct fsck_instance *inst2;
534		for (inst2 = instance_list; inst2; inst2 = inst2->next) {
535			if (inst2->flags & FLAG_DONE)
536				continue;
537			if (strcmp(inst2->type, "ext2") != 0
538			 && strcmp(inst2->type, "ext3") != 0
539			) {
540				continue;
541			}
542			/* ext[23], we will send USR1
543			 * (request to start displaying progress bar)
544			 *
545			 * If we've just started the fsck, wait a tiny
546			 * bit before sending the kill, to give it
547			 * time to set up the signal handler
548			 */
549			if (inst2->start_time >= time(NULL) - 1)
550				sleep(1);
551			kill(inst2->pid, SIGUSR1);
552			inst2->flags |= FLAG_PROGRESS;
553			break;
554		}
555	}
556#endif
557
558 ret_inst:
559	if (prev)
560		prev->next = inst->next;
561	else
562		instance_list = inst->next;
563	if (verbose > 1)
564		printf("Finished with %s (exit status %d)\n",
565		       inst->device, inst->exit_status);
566	num_running--;
567	return inst;
568}
569
570#define FLAG_WAIT_ALL           0
571#define FLAG_WAIT_ATLEAST_ONE   1
572/*
573 * Wait until all executing child processes have exited; return the
574 * logical OR of all of their exit code values.
575 */
576static int wait_many(int flags)
577{
578	struct fsck_instance *inst;
579	int global_status = 0;
580	int wait_flags = 0;
581
582	while ((inst = wait_one(wait_flags))) {
583		global_status |= inst->exit_status;
584		free_instance(inst);
585#ifdef RANDOM_DEBUG
586		if (noexecute && (flags & WNOHANG) && !(random() % 3))
587			break;
588#endif
589		if (flags & FLAG_WAIT_ATLEAST_ONE)
590			wait_flags = WNOHANG;
591	}
592	return global_status;
593}
594
595/*
596 * Execute a particular fsck program, and link it into the list of
597 * child processes we are waiting for.
598 */
599static void execute(const char *type, const char *device, const char *mntpt,
600		int interactive)
601{
602	char *argv[num_args + 4]; /* see count below: */
603	int argc;
604	int i;
605	struct fsck_instance *inst;
606	pid_t pid;
607
608	inst = xzalloc(sizeof(*inst));
609
610	argv[0] = xasprintf("fsck.%s", type); /* 1 */
611	for (i = 0; i < num_args; i++)
612		argv[i+1] = args[i]; /* num_args */
613	argc = num_args + 1;
614
615#if DO_PROGRESS_INDICATOR
616	if (progress && !progress_active()) {
617		if (strcmp(type, "ext2") == 0
618		 || strcmp(type, "ext3") == 0
619		) {
620			argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */
621			inst->flags |= FLAG_PROGRESS;
622		}
623	}
624#endif
625
626	argv[argc++] = xstrdup(device); /* 1 */
627	argv[argc] = NULL; /* 1 */
628
629	if (verbose || noexecute) {
630		printf("[%s (%d) -- %s]", argv[0], num_running,
631					mntpt ? mntpt : device);
632		for (i = 0; i < argc; i++)
633			printf(" %s", argv[i]);
634		puts("");
635	}
636
637	/* Fork and execute the correct program. */
638	pid = -1;
639	if (!noexecute) {
640		pid = spawn(argv);
641		if (pid < 0)
642			bb_perror_msg("%s", argv[0]);
643	}
644
645	for (i = num_args+1; i < argc; i++)
646		free(argv[i]);
647
648	inst->pid = pid;
649	inst->prog = argv[0];
650	inst->type = xstrdup(type);
651	inst->device = xstrdup(device);
652	inst->base_device = base_device(device);
653	inst->start_time = time(NULL);
654
655	/* Add to the list of running fsck's.
656	 * (was adding to the end, but adding to the front is simpler...) */
657	inst->next = instance_list;
658	instance_list = inst;
659}
660
661/*
662 * Run the fsck program on a particular device
663 *
664 * If the type is specified using -t, and it isn't prefixed with "no"
665 * (as in "noext2") and only one filesystem type is specified, then
666 * use that type regardless of what is specified in /etc/fstab.
667 *
668 * If the type isn't specified by the user, then use either the type
669 * specified in /etc/fstab, or "auto".
670 */
671static void fsck_device(struct fs_info *fs, int interactive)
672{
673	const char *type;
674
675	if (strcmp(fs->type, "auto") != 0) {
676		type = fs->type;
677		if (verbose > 2)
678			bb_info_msg("using filesystem type '%s' %s",
679					type, "from fstab");
680	} else if (fstype
681	 && (fstype[0] != 'n' || fstype[1] != 'o') /* != "no" */
682	 && strncmp(fstype, "opts=", 5) != 0
683	 && strncmp(fstype, "loop", 4) != 0
684	 && !strchr(fstype, ',')
685	) {
686		type = fstype;
687		if (verbose > 2)
688			bb_info_msg("using filesystem type '%s' %s",
689					type, "from -t");
690	} else {
691		type = "auto";
692		if (verbose > 2)
693			bb_info_msg("using filesystem type '%s' %s",
694					type, "(default)");
695	}
696
697	num_running++;
698	execute(type, fs->device, fs->mountpt, interactive);
699}
700
701/*
702 * Returns TRUE if a partition on the same disk is already being
703 * checked.
704 */
705static int device_already_active(char *device)
706{
707	struct fsck_instance *inst;
708	char *base;
709
710	if (force_all_parallel)
711		return 0;
712
713#ifdef BASE_MD
714	/* Don't check a soft raid disk with any other disk */
715	if (instance_list
716	 && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1)
717	     || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))
718	) {
719		return 1;
720	}
721#endif
722
723	base = base_device(device);
724	/*
725	 * If we don't know the base device, assume that the device is
726	 * already active if there are any fsck instances running.
727	 */
728	if (!base)
729		return (instance_list != NULL);
730
731	for (inst = instance_list; inst; inst = inst->next) {
732		if (!inst->base_device || !strcmp(base, inst->base_device)) {
733			free(base);
734			return 1;
735		}
736	}
737
738	free(base);
739	return 0;
740}
741
742/*
743 * This function returns true if a particular option appears in a
744 * comma-delimited options list
745 */
746static int opt_in_list(char *opt, char *optlist)
747{
748	char *s;
749	int len;
750
751	if (!optlist)
752		return 0;
753
754	len = strlen(opt);
755	s = optlist - 1;
756	while (1) {
757		s = strstr(s + 1, opt);
758		if (!s)
759			return 0;
760		if (s != optlist && s[-1] != ',')
761			continue;
762		if (s[len] != '\0' && s[len] != ',')
763			continue;
764		return 1;
765	}
766}
767
768/* See if the filesystem matches the criteria given by the -t option */
769static int fs_match(struct fs_info *fs)
770{
771	int n, ret, checked_type;
772	char *cp;
773
774	if (!fs_type_list)
775		return 1;
776
777	ret = 0;
778	checked_type = 0;
779	n = 0;
780	while (1) {
781		cp = fs_type_list[n];
782		if (!cp)
783			break;
784		switch (fs_type_flag[n]) {
785		case FS_TYPE_FLAG_NORMAL:
786			checked_type++;
787			if (strcmp(cp, fs->type) == 0)
788				ret = 1;
789			break;
790		case FS_TYPE_FLAG_NEGOPT:
791			if (opt_in_list(cp, fs->opts))
792				return 0;
793			break;
794		case FS_TYPE_FLAG_OPT:
795			if (!opt_in_list(cp, fs->opts))
796				return 0;
797			break;
798		}
799		n++;
800	}
801	if (checked_type == 0)
802		return 1;
803
804	return (fs_type_negated ? !ret : ret);
805}
806
807/* Check if we should ignore this filesystem. */
808static int ignore(struct fs_info *fs)
809{
810	/*
811	 * If the pass number is 0, ignore it.
812	 */
813	if (fs->passno == 0)
814		return 1;
815
816	/*
817	 * If a specific fstype is specified, and it doesn't match,
818	 * ignore it.
819	 */
820	if (!fs_match(fs))
821		return 1;
822
823	/* Are we ignoring this type? */
824	if (index_in_strings(ignored_types, fs->type) >= 0)
825		return 1;
826
827	/* We can and want to check this file system type. */
828	return 0;
829}
830
831/* Check all file systems, using the /etc/fstab table. */
832static int check_all(void)
833{
834	struct fs_info *fs;
835	int status = EXIT_OK;
836	smallint not_done_yet;
837	smallint pass_done;
838	int passno;
839
840	if (verbose)
841		puts("Checking all filesystems");
842
843	/*
844	 * Do an initial scan over the filesystem; mark filesystems
845	 * which should be ignored as done, and resolve any "auto"
846	 * filesystem types (done as a side-effect of calling ignore()).
847	 */
848	for (fs = filesys_info; fs; fs = fs->next) {
849		if (ignore(fs))
850			fs->flags |= FLAG_DONE;
851	}
852
853	/*
854	 * Find and check the root filesystem.
855	 */
856	if (!parallel_root) {
857		for (fs = filesys_info; fs; fs = fs->next) {
858			if (LONE_CHAR(fs->mountpt, '/'))
859				break;
860		}
861		if (fs) {
862			if (!skip_root && !ignore(fs)) {
863				fsck_device(fs, 1);
864				status |= wait_many(FLAG_WAIT_ALL);
865				if (status > EXIT_NONDESTRUCT)
866					return status;
867			}
868			fs->flags |= FLAG_DONE;
869		}
870	}
871	/*
872	 * This is for the bone-headed user who enters the root
873	 * filesystem twice.  Skip root will skip all root entries.
874	 */
875	if (skip_root)
876		for (fs = filesys_info; fs; fs = fs->next)
877			if (LONE_CHAR(fs->mountpt, '/'))
878				fs->flags |= FLAG_DONE;
879
880	not_done_yet = 1;
881	passno = 1;
882	while (not_done_yet) {
883		not_done_yet = 0;
884		pass_done = 1;
885
886		for (fs = filesys_info; fs; fs = fs->next) {
887			if (cancel_requested)
888				break;
889			if (fs->flags & FLAG_DONE)
890				continue;
891			/*
892			 * If the filesystem's pass number is higher
893			 * than the current pass number, then we don't
894			 * do it yet.
895			 */
896			if (fs->passno > passno) {
897				not_done_yet = 1;
898				continue;
899			}
900			/*
901			 * If a filesystem on a particular device has
902			 * already been spawned, then we need to defer
903			 * this to another pass.
904			 */
905			if (device_already_active(fs->device)) {
906				pass_done = 0;
907				continue;
908			}
909			/*
910			 * Spawn off the fsck process
911			 */
912			fsck_device(fs, serialize);
913			fs->flags |= FLAG_DONE;
914
915			/*
916			 * Only do one filesystem at a time, or if we
917			 * have a limit on the number of fsck's extant
918			 * at one time, apply that limit.
919			 */
920			if (serialize
921			 || (max_running && (num_running >= max_running))
922			) {
923				pass_done = 0;
924				break;
925			}
926		}
927		if (cancel_requested)
928			break;
929		if (verbose > 1)
930			printf("--waiting-- (pass %d)\n", passno);
931		status |= wait_many(pass_done ? FLAG_WAIT_ALL :
932				    FLAG_WAIT_ATLEAST_ONE);
933		if (pass_done) {
934			if (verbose > 1)
935				puts("----------------------------------");
936			passno++;
937		} else
938			not_done_yet = 1;
939	}
940	kill_all_if_cancel_requested();
941	status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
942	return status;
943}
944
945/*
946 * Deal with the fsck -t argument.
947 * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
948 * Why here we require "-t novfat,nonfs" ??
949 */
950static void compile_fs_type(char *fs_type)
951{
952	char *s;
953	int num = 2;
954	smallint negate;
955
956	if (fs_type) {
957		s = fs_type;
958		while ((s = strchr(s, ','))) {
959			num++;
960			s++;
961		}
962	}
963
964	fs_type_list = xzalloc(num * sizeof(fs_type_list[0]));
965	fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0]));
966	fs_type_negated = -1; /* not yet known is it negated or not */
967
968	if (!fs_type)
969		return;
970
971	num = 0;
972	s = fs_type;
973	while (1) {
974		char *comma;
975
976		negate = 0;
977		if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
978			s += 2;
979			negate = 1;
980		} else if (s[0] == '!') {
981			s++;
982			negate = 1;
983		}
984
985		if (strcmp(s, "loop") == 0)
986			/* loop is really short-hand for opts=loop */
987			goto loop_special_case;
988		if (strncmp(s, "opts=", 5) == 0) {
989			s += 5;
990 loop_special_case:
991			fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
992		} else {
993			if (fs_type_negated == -1)
994				fs_type_negated = negate;
995			if (fs_type_negated != negate)
996				bb_error_msg_and_die(
997"either all or none of the filesystem types passed to -t must be prefixed "
998"with 'no' or '!'");
999		}
1000		comma = strchr(s, ',');
1001		fs_type_list[num++] = comma ? xstrndup(s, comma-s) : xstrdup(s);
1002		if (!comma)
1003			break;
1004		s = comma + 1;
1005	}
1006}
1007
1008static void parse_args(int argc, char **argv)
1009{
1010	int i, j;
1011	char *arg, *tmp;
1012	char *options = NULL;
1013	int optpos = 0;
1014	int opts_for_fsck = 0;
1015
1016	/* in bss, so already zeroed
1017	num_devices = 0;
1018	num_args = 0;
1019	instance_list = NULL;
1020	*/
1021
1022/* TODO: getopt32 */
1023	for (i = 1; i < argc; i++) {
1024		arg = argv[i];
1025
1026		if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
1027			devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0]));
1028			devices[num_devices++] = xstrdup(arg);
1029			continue;
1030		}
1031
1032		if (arg[0] != '-' || opts_for_fsck) {
1033			args = xrealloc(args, (num_args+1) * sizeof(args[0]));
1034			args[num_args++] = xstrdup(arg);
1035			continue;
1036		}
1037
1038		for (j = 1; arg[j]; j++) {
1039			if (opts_for_fsck) {
1040				optpos++;
1041				/* one extra for '\0' */
1042				options = xrealloc(options, optpos + 2);
1043				options[optpos] = arg[j];
1044				continue;
1045			}
1046			switch (arg[j]) {
1047			case 'A':
1048				doall = 1;
1049				break;
1050#if DO_PROGRESS_INDICATOR
1051			case 'C':
1052				progress = 1;
1053				if (arg[++j]) { /* -Cn */
1054					progress_fd = xatoi_u(&arg[j]);
1055					goto next_arg;
1056				}
1057				/* -C n */
1058				progress_fd = xatoi_u(argv[++i]);
1059				goto next_arg;
1060#endif
1061			case 'V':
1062				verbose++;
1063				break;
1064			case 'N':
1065				noexecute = 1;
1066				break;
1067			case 'R':
1068				skip_root = 1;
1069				break;
1070			case 'T':
1071				notitle = 1;
1072				break;
1073/*			case 'M':
1074				like_mount = 1;
1075				break; */
1076			case 'P':
1077				parallel_root = 1;
1078				break;
1079			case 's':
1080				serialize = 1;
1081				break;
1082			case 't':
1083				if (fstype)
1084					bb_show_usage();
1085				if (arg[++j])
1086					tmp = &arg[j];
1087				else if (++i < argc)
1088					tmp = argv[i];
1089				else
1090					bb_show_usage();
1091				fstype = xstrdup(tmp);
1092				compile_fs_type(fstype);
1093				goto next_arg;
1094			case '-':
1095				opts_for_fsck++;
1096				break;
1097			case '?':
1098				bb_show_usage();
1099				break;
1100			default:
1101				optpos++;
1102				/* one extra for '\0' */
1103				options = xrealloc(options, optpos + 2);
1104				options[optpos] = arg[j];
1105				break;
1106			}
1107		}
1108 next_arg:
1109		if (optpos) {
1110			options[0] = '-';
1111			options[optpos + 1] = '\0';
1112			args = xrealloc(args, (num_args+1) * sizeof(args[0]));
1113			args[num_args++] = options;
1114			optpos = 0;
1115			options = NULL;
1116		}
1117	}
1118	if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1119		force_all_parallel = 1;
1120	tmp = getenv("FSCK_MAX_INST");
1121	if (tmp)
1122		max_running = xatoi(tmp);
1123}
1124
1125static void signal_cancel(int sig ATTRIBUTE_UNUSED)
1126{
1127	cancel_requested = 1;
1128}
1129
1130int fsck_main(int argc, char **argv);
1131int fsck_main(int argc, char **argv)
1132{
1133	int i, status = 0;
1134	int interactive;
1135	const char *fstab;
1136	struct fs_info *fs;
1137	struct sigaction sa;
1138
1139	memset(&sa, 0, sizeof(sa));
1140	sa.sa_handler = signal_cancel;
1141	sigaction(SIGINT, &sa, 0);
1142	sigaction(SIGTERM, &sa, 0);
1143
1144	setbuf(stdout, NULL);
1145
1146	parse_args(argc, argv);
1147
1148	if (!notitle)
1149		puts("fsck (busybox "BB_VER", "BB_BT")");
1150
1151	/* Even plain "fsck /dev/hda1" needs fstab to get fs type,
1152	 * so we are scanning it anyway */
1153	fstab = getenv("FSTAB_FILE");
1154	if (!fstab)
1155		fstab = "/etc/fstab";
1156	load_fs_info(fstab);
1157
1158	interactive = (num_devices == 1) | serialize;
1159
1160	/* If -A was specified ("check all"), do that! */
1161	if (doall)
1162		return check_all();
1163
1164	if (num_devices == 0) {
1165		serialize = 1;
1166		interactive = 1;
1167		return check_all();
1168	}
1169
1170	for (i = 0; i < num_devices; i++) {
1171		if (cancel_requested) {
1172			kill_all_if_cancel_requested();
1173			break;
1174		}
1175
1176		fs = lookup(devices[i]);
1177		if (!fs)
1178			fs = create_fs_device(devices[i], 0, "auto", 0, -1, -1);
1179		fsck_device(fs, interactive);
1180
1181		if (serialize
1182		 || (max_running && (num_running >= max_running))
1183		) {
1184			struct fsck_instance *inst;
1185
1186			inst = wait_one(0);
1187			if (inst) {
1188				status |= inst->exit_status;
1189				free_instance(inst);
1190			}
1191			if (verbose > 1)
1192				puts("----------------------------------");
1193		}
1194	}
1195	status |= wait_many(FLAG_WAIT_ALL);
1196	return status;
1197}
1198