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