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