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