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