source: MondoRescue/branches/stable/mindi-busybox/e2fsprogs/fsck.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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