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