source: MondoRescue/branches/3.3/mindi-busybox/e2fsprogs/fsck.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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