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