fsck.c revision 793e27df7312d5b217c172387f71fd581ed30c82
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	for (inst = instance_list; inst; inst = inst->next) {
702		if (!strcmp(base, inst->base_device)) {
703			free(base);
704			return 1;
705		}
706	}
707	free(base);
708	return 0;
709}
710
711/* Check all file systems, using the /etc/fstab table. */
712static int check_all(NOARGS)
713{
714	struct fs_info *fs = NULL;
715	struct fsck_instance *inst;
716	int status = EXIT_OK;
717	int not_done_yet = 1;
718	int passno = 1;
719	int pass_done;
720
721	if (verbose)
722		printf(_("Checking all file systems.\n"));
723
724	/*
725	 * Find and check the root filesystem first.
726	 */
727	if (!parallel_root) {
728		for (fs = filesys_info; fs; fs = fs->next) {
729			if (!strcmp(fs->mountpt, "/"))
730				break;
731		}
732		if (fs && !skip_root && !ignore(fs)) {
733			fs->device = interpret_device(fs->device);
734			fsck_device(fs->device, 1);
735			fs->flags |= FLAG_DONE;
736			status |= wait_all();
737			if (status > EXIT_NONDESTRUCT)
738				return status;
739		}
740	}
741	if (fs) fs->flags |= FLAG_DONE;
742
743	/*
744	 * Mark filesystems that should be ignored as done.
745	 */
746	for (fs = filesys_info; fs; fs = fs->next) {
747		if (ignore(fs))
748			fs->flags |= FLAG_DONE;
749	}
750
751	while (not_done_yet) {
752		not_done_yet = 0;
753		pass_done = 1;
754
755		for (fs = filesys_info; fs; fs = fs->next) {
756			if (fs->flags & FLAG_DONE)
757				continue;
758			/*
759			 * If the filesystem's pass number is higher
760			 * than the current pass number, then we don't
761			 * do it yet.
762			 */
763			if (fs->passno > passno) {
764				not_done_yet++;
765				continue;
766			}
767			/*
768			 * If a filesystem on a particular device has
769			 * already been spawned, then we need to defer
770			 * this to another pass.
771			 */
772			if (device_already_active(fs->device)) {
773				pass_done = 0;
774				continue;
775			}
776			/*
777			 * Spawn off the fsck process
778			 */
779			fs->device = interpret_device(fs->device);
780			fsck_device(fs->device, serialize);
781			fs->flags |= FLAG_DONE;
782
783			if (serialize) {
784				pass_done = 0;
785				break; /* Only do one filesystem at a time */
786			}
787		}
788		if (verbose > 1)
789			printf(_("--waiting-- (pass %d)\n"), passno);
790		inst = wait_one();
791		if (inst) {
792			status |= inst->exit_status;
793			free_instance(inst);
794		}
795		if (pass_done) {
796			status |= wait_all();
797			if (verbose > 1)
798				printf("----------------------------------\n");
799			passno++;
800		} else
801			not_done_yet++;
802	}
803	status |= wait_all();
804	return status;
805}
806
807static void usage(NOARGS)
808{
809	fprintf(stderr,
810		_("Usage: fsck [-ACNPRTV] [-t fstype] [fs-options] filesys\n"));
811	exit(EXIT_USAGE);
812}
813
814static void PRS(int argc, char *argv[])
815{
816	int	i, j;
817	char	*arg;
818	char	options[128];
819	int	opt = 0;
820	int     opts_for_fsck = 0;
821
822	num_devices = 0;
823	num_args = 0;
824	instance_list = 0;
825
826	progname = argv[0];
827
828	for (i=1; i < argc; i++) {
829		arg = argv[i];
830		if (!arg)
831			continue;
832		if ((arg[0] == '/' && !opts_for_fsck) ||
833		    (strncmp(arg, "LABEL=", 6) == 0) ||
834		    (strncmp(arg, "UUID=", 5) == 0)) {
835			if (num_devices >= MAX_DEVICES) {
836				fprintf(stderr, _("%s: too many devices\n"),
837					progname);
838				exit(1);
839			}
840			devices[num_devices++] =
841				interpret_device(string_copy(arg));
842			continue;
843		}
844		if (arg[0] != '-' || opts_for_fsck) {
845			if (num_args >= MAX_ARGS) {
846				fprintf(stderr, _("%s: too many arguments\n"),
847					progname);
848				exit(1);
849			}
850			args[num_args++] = string_copy(arg);
851			continue;
852		}
853		for (j=1; arg[j]; j++) {
854			if (opts_for_fsck) {
855				options[++opt] = arg[j];
856				continue;
857			}
858			switch (arg[j]) {
859			case 'A':
860				doall++;
861				break;
862			case 'C':
863				progress++;
864				break;
865			case 'V':
866				verbose++;
867				break;
868			case 'N':
869				noexecute++;
870				break;
871			case 'R':
872				skip_root++;
873				break;
874			case 'T':
875				notitle++;
876				break;
877			case 'M':
878				like_mount++;
879				break;
880			case 'P':
881				parallel_root++;
882				break;
883			case 's':
884				serialize++;
885				break;
886			case 't':
887				if (arg[j+1]) {
888					fstype = string_copy(arg+j+1);
889					goto next_arg;
890				}
891				if ((i+1) < argc) {
892					i++;
893					fstype = string_copy(argv[i]);
894					goto next_arg;
895				}
896				usage();
897				break;
898			case '-':
899				opts_for_fsck++;
900				break;
901			default:
902				options[++opt] = arg[j];
903				break;
904			}
905		}
906	next_arg:
907		if (opt) {
908			options[0] = '-';
909			options[++opt] = '\0';
910			if (num_args >= MAX_ARGS) {
911				fprintf(stderr,
912					_("%s: too many arguments\n"),
913					progname);
914				exit(1);
915			}
916			args[num_args++] = string_copy(options);
917			opt = 0;
918		}
919	}
920	if (getenv("FSCK_FORCE_ALL_PARALLEL"))
921		force_all_parallel++;
922}
923
924int main(int argc, char *argv[])
925{
926	int i;
927	int status = 0;
928	int interactive = 0;
929	char *oldpath = getenv("PATH");
930	const char *fstab;
931
932#ifdef ENABLE_NLS
933	setlocale(LC_MESSAGES, "");
934	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
935	textdomain(NLS_CAT_NAME);
936#endif
937	PRS(argc, argv);
938
939	if (!notitle)
940		printf(_("Parallelizing fsck version %s (%s)\n"),
941			E2FSPROGS_VERSION, E2FSPROGS_DATE);
942
943	fstab = getenv("FSTAB_FILE");
944	if (!fstab)
945		fstab = _PATH_MNTTAB;
946	load_fs_info(fstab);
947
948	/* Update our search path to include uncommon directories. */
949	if (oldpath) {
950		fsck_path = malloc (strlen (fsck_prefix_path) + 1 +
951				    strlen (oldpath) + 1);
952		strcpy (fsck_path, fsck_prefix_path);
953		strcat (fsck_path, ":");
954		strcat (fsck_path, oldpath);
955	} else {
956		fsck_path = string_copy(fsck_prefix_path);
957	}
958
959	if ((num_devices == 1) || (serialize))
960		interactive = 1;
961
962	/* If -A was specified ("check all"), do that! */
963	if (doall)
964		return check_all();
965
966	for (i = 0 ; i < num_devices; i++) {
967		fsck_device(devices[i], interactive);
968		if (serialize) {
969			struct fsck_instance *inst;
970
971			inst = wait_one();
972			if (inst) {
973				status |= inst->exit_status;
974				free_instance(inst);
975			}
976		}
977	}
978	status |= wait_all();
979	free(fsck_path);
980	return status;
981}
982