37 |
* It doesn't guess filesystem types from on-disk format. |
* It doesn't guess filesystem types from on-disk format. |
38 |
*/ |
*/ |
39 |
|
|
40 |
#include "busybox.h" |
#include "libbb.h" |
41 |
|
|
42 |
|
/* "progress indicator" code is somewhat buggy and ext[23] specific. |
43 |
|
* We should be filesystem agnostic. IOW: there should be a well-defined |
44 |
|
* API for fsck.something, NOT ad-hoc hacks in generic fsck. */ |
45 |
|
#define DO_PROGRESS_INDICATOR 0 |
46 |
|
|
47 |
#define EXIT_OK 0 |
#define EXIT_OK 0 |
48 |
#define EXIT_NONDESTRUCT 1 |
#define EXIT_NONDESTRUCT 1 |
62 |
char *mountpt; |
char *mountpt; |
63 |
char *type; |
char *type; |
64 |
char *opts; |
char *opts; |
|
int freq; |
|
65 |
int passno; |
int passno; |
66 |
int flags; |
int flags; |
67 |
}; |
}; |
75 |
struct fsck_instance *next; |
struct fsck_instance *next; |
76 |
int pid; |
int pid; |
77 |
int flags; |
int flags; |
78 |
int exit_status; |
#if DO_PROGRESS_INDICATOR |
79 |
time_t start_time; |
time_t start_time; |
80 |
|
#endif |
81 |
char *prog; |
char *prog; |
|
char *type; |
|
82 |
char *device; |
char *device; |
83 |
char *base_device; /* /dev/hda for /dev/hdaN etc */ |
char *base_device; /* /dev/hda for /dev/hdaN etc */ |
84 |
}; |
}; |
85 |
|
|
86 |
static const char *const ignored_types[] = { |
static const char ignored_types[] ALIGN1 = |
87 |
"ignore", |
"ignore\0" |
88 |
"iso9660", |
"iso9660\0" |
89 |
"nfs", |
"nfs\0" |
90 |
"proc", |
"proc\0" |
91 |
"sw", |
"sw\0" |
92 |
"swap", |
"swap\0" |
93 |
"tmpfs", |
"tmpfs\0" |
94 |
"devpts", |
"devpts\0"; |
|
NULL |
|
|
}; |
|
95 |
|
|
96 |
#if 0 |
#if 0 |
97 |
static const char *const really_wanted[] = { |
static const char really_wanted[] ALIGN1 = |
98 |
"minix", |
"minix\0" |
99 |
"ext2", |
"ext2\0" |
100 |
"ext3", |
"ext3\0" |
101 |
"jfs", |
"jfs\0" |
102 |
"reiserfs", |
"reiserfs\0" |
103 |
"xiafs", |
"xiafs\0" |
104 |
"xfs", |
"xfs\0"; |
|
NULL |
|
|
}; |
|
105 |
#endif |
#endif |
106 |
|
|
107 |
#define BASE_MD "/dev/md" |
#define BASE_MD "/dev/md" |
129 |
static smallint parallel_root; |
static smallint parallel_root; |
130 |
static smallint force_all_parallel; |
static smallint force_all_parallel; |
131 |
|
|
|
/* "progress indicator" code is somewhat buggy and ext[23] specific. |
|
|
* We should be filesystem agnostic. IOW: there should be a well-defined |
|
|
* API for fsck.something, NOT ad-hoc hacks in generic fsck. */ |
|
|
#define DO_PROGRESS_INDICATOR 0 |
|
132 |
#if DO_PROGRESS_INDICATOR |
#if DO_PROGRESS_INDICATOR |
133 |
static smallint progress; |
static smallint progress; |
134 |
static int progress_fd; |
static int progress_fd; |
273 |
|
|
274 |
static struct fs_info *create_fs_device(const char *device, const char *mntpnt, |
static struct fs_info *create_fs_device(const char *device, const char *mntpnt, |
275 |
const char *type, const char *opts, |
const char *type, const char *opts, |
276 |
int freq, int passno) |
int passno) |
277 |
{ |
{ |
278 |
struct fs_info *fs; |
struct fs_info *fs; |
279 |
|
|
280 |
fs = xzalloc(sizeof(*fs)); |
fs = xzalloc(sizeof(*fs)); |
281 |
fs->device = xstrdup(device); |
fs->device = xstrdup(device); |
282 |
fs->mountpt = xstrdup(mntpnt); |
fs->mountpt = xstrdup(mntpnt); |
283 |
|
if (strchr(type, ',')) |
284 |
|
type = (char *)"auto"; |
285 |
fs->type = xstrdup(type); |
fs->type = xstrdup(type); |
286 |
fs->opts = xstrdup(opts ? opts : ""); |
fs->opts = xstrdup(opts ? opts : ""); |
287 |
fs->freq = freq; |
fs->passno = passno < 0 ? 1 : passno; |
|
fs->passno = passno; |
|
288 |
/*fs->flags = 0; */ |
/*fs->flags = 0; */ |
289 |
/*fs->next = NULL; */ |
/*fs->next = NULL; */ |
290 |
|
|
297 |
return fs; |
return fs; |
298 |
} |
} |
299 |
|
|
|
static void strip_line(char *line) |
|
|
{ |
|
|
char *p = line + strlen(line) - 1; |
|
|
|
|
|
while (*line) { |
|
|
if (*p != '\n' && *p != '\r') |
|
|
break; |
|
|
*p-- = '\0'; |
|
|
} |
|
|
} |
|
|
|
|
|
static char *parse_word(char **buf) |
|
|
{ |
|
|
char *word, *next; |
|
|
|
|
|
word = *buf; |
|
|
if (*word == '\0') |
|
|
return NULL; |
|
|
|
|
|
word = skip_whitespace(word); |
|
|
next = skip_non_whitespace(word); |
|
|
if (*next) |
|
|
*next++ = '\0'; |
|
|
*buf = next; |
|
|
return word; |
|
|
} |
|
|
|
|
|
static void parse_escape(char *word) |
|
|
{ |
|
|
char *q, c; |
|
|
const char *p; |
|
|
|
|
|
if (!word) |
|
|
return; |
|
|
|
|
|
for (p = q = word; *p; q++) { |
|
|
c = *p++; |
|
|
if (c != '\\') { |
|
|
*q = c; |
|
|
} else { |
|
|
*q = bb_process_escape_sequence(&p); |
|
|
} |
|
|
} |
|
|
*q = '\0'; |
|
|
} |
|
|
|
|
|
static int parse_fstab_line(char *line, struct fs_info **ret_fs) |
|
|
{ |
|
|
char *device, *mntpnt, *type, *opts, *freq, *passno, *cp; |
|
|
struct fs_info *fs; |
|
|
|
|
|
*ret_fs = 0; |
|
|
strip_line(line); |
|
|
cp = strchr(line, '#'); |
|
|
if (cp) |
|
|
*cp = '\0'; /* Ignore everything after the comment char */ |
|
|
cp = line; |
|
|
|
|
|
device = parse_word(&cp); |
|
|
if (!device) return 0; /* Allow blank lines */ |
|
|
mntpnt = parse_word(&cp); |
|
|
type = parse_word(&cp); |
|
|
opts = parse_word(&cp); |
|
|
freq = parse_word(&cp); |
|
|
passno = parse_word(&cp); |
|
|
|
|
|
if (!mntpnt || !type) |
|
|
return -1; |
|
|
|
|
|
parse_escape(device); |
|
|
parse_escape(mntpnt); |
|
|
parse_escape(type); |
|
|
parse_escape(opts); |
|
|
parse_escape(freq); |
|
|
parse_escape(passno); |
|
|
|
|
|
if (strchr(type, ',')) |
|
|
type = NULL; |
|
|
|
|
|
fs = create_fs_device(device, mntpnt, type ? type : "auto", opts, |
|
|
freq ? atoi(freq) : -1, |
|
|
passno ? atoi(passno) : -1); |
|
|
*ret_fs = fs; |
|
|
return 0; |
|
|
} |
|
|
|
|
300 |
/* Load the filesystem database from /etc/fstab */ |
/* Load the filesystem database from /etc/fstab */ |
301 |
static void load_fs_info(const char *filename) |
static void load_fs_info(const char *filename) |
302 |
{ |
{ |
303 |
FILE *f; |
FILE *fstab; |
304 |
int lineno = 0; |
struct mntent mte; |
|
int old_fstab = 1; |
|
305 |
struct fs_info *fs; |
struct fs_info *fs; |
306 |
|
|
307 |
f = fopen_or_warn(filename, "r"); |
fstab = setmntent(filename, "r"); |
308 |
if (f == NULL) { |
if (!fstab) { |
309 |
/*bb_perror_msg("WARNING: cannot open %s", filename);*/ |
bb_perror_msg("cannot read %s", filename); |
310 |
return; |
return; |
311 |
} |
} |
312 |
while (1) { |
|
313 |
int r; |
// Loop through entries |
314 |
char *buf = xmalloc_getline(f); |
while (getmntent_r(fstab, &mte, bb_common_bufsiz1, COMMON_BUFSIZE)) { |
315 |
if (!buf) break; |
//bb_info_msg("CREATE[%s][%s][%s][%s][%d]", mte.mnt_fsname, mte.mnt_dir, |
316 |
r = parse_fstab_line(buf, &fs); |
// mte.mnt_type, mte.mnt_opts, |
317 |
free(buf); |
// mte.mnt_passno); |
318 |
lineno++; |
fs = create_fs_device(mte.mnt_fsname, mte.mnt_dir, |
319 |
if (r < 0) { |
mte.mnt_type, mte.mnt_opts, |
320 |
bb_error_msg("WARNING: bad format " |
mte.mnt_passno); |
|
"on line %d of %s", lineno, filename); |
|
|
continue; |
|
|
} |
|
|
if (!fs) |
|
|
continue; |
|
|
if (fs->passno < 0) |
|
|
fs->passno = 0; |
|
|
else |
|
|
old_fstab = 0; |
|
|
} |
|
|
fclose(f); |
|
|
|
|
|
if (old_fstab) { |
|
|
fputs("\007" |
|
|
"WARNING: Your /etc/fstab does not contain the fsck passno field.\n" |
|
|
"I will kludge around things for you, but you should fix\n" |
|
|
"your /etc/fstab file as soon as you can.\n\n", stderr); |
|
|
for (fs = filesys_info; fs; fs = fs->next) { |
|
|
fs->passno = 1; |
|
|
} |
|
321 |
} |
} |
322 |
|
endmntent(fstab); |
323 |
} |
} |
324 |
|
|
325 |
/* Lookup filesys in /etc/fstab and return the corresponding entry. */ |
/* Lookup filesys in /etc/fstab and return the corresponding entry. */ |
375 |
|
|
376 |
/* |
/* |
377 |
* Wait for one child process to exit; when it does, unlink it from |
* Wait for one child process to exit; when it does, unlink it from |
378 |
* the list of executing child processes, and return it. |
* the list of executing child processes, free, and return its exit status. |
379 |
|
* If there is no exited child, return -1. |
380 |
*/ |
*/ |
381 |
static struct fsck_instance *wait_one(int flags) |
static int wait_one(int flags) |
382 |
{ |
{ |
383 |
int status; |
int status; |
384 |
int sig; |
int sig; |
386 |
pid_t pid; |
pid_t pid; |
387 |
|
|
388 |
if (!instance_list) |
if (!instance_list) |
389 |
return NULL; |
return -1; |
390 |
|
/* if (noexecute) { already returned -1; } */ |
|
if (noexecute) { |
|
|
inst = instance_list; |
|
|
prev = NULL; |
|
|
#ifdef RANDOM_DEBUG |
|
|
while (inst->next && (random() & 1)) { |
|
|
prev = inst; |
|
|
inst = inst->next; |
|
|
} |
|
|
#endif |
|
|
inst->exit_status = 0; |
|
|
goto ret_inst; |
|
|
} |
|
|
|
|
|
/* |
|
|
* gcc -Wall fails saving throw against stupidity |
|
|
* (inst and prev are thought to be uninitialized variables) |
|
|
*/ |
|
|
inst = prev = NULL; |
|
391 |
|
|
392 |
do { |
while (1) { |
393 |
pid = waitpid(-1, &status, flags); |
pid = waitpid(-1, &status, flags); |
394 |
kill_all_if_cancel_requested(); |
kill_all_if_cancel_requested(); |
395 |
if (pid == 0 && (flags & WNOHANG)) |
if (pid == 0) /* flags == WNOHANG and no children exited */ |
396 |
return NULL; |
return -1; |
397 |
if (pid < 0) { |
if (pid < 0) { |
398 |
if (errno == EINTR || errno == EAGAIN) |
if (errno == EINTR) |
399 |
continue; |
continue; |
400 |
if (errno == ECHILD) { |
if (errno == ECHILD) { /* paranoia */ |
401 |
bb_error_msg("wait: no more child process?!?"); |
bb_error_msg("wait: no more children"); |
402 |
return NULL; |
return -1; |
403 |
} |
} |
404 |
bb_perror_msg("wait"); |
bb_perror_msg("wait"); |
405 |
continue; |
continue; |
406 |
} |
} |
407 |
prev = NULL; |
prev = NULL; |
408 |
inst = instance_list; |
inst = instance_list; |
409 |
while (inst) { |
do { |
410 |
if (inst->pid == pid) |
if (inst->pid == pid) |
411 |
break; |
goto child_died; |
412 |
prev = inst; |
prev = inst; |
413 |
inst = inst->next; |
inst = inst->next; |
414 |
} |
} while (inst); |
415 |
} while (!inst); |
} |
416 |
|
child_died: |
417 |
|
|
418 |
if (WIFEXITED(status)) |
if (WIFEXITED(status)) |
419 |
status = WEXITSTATUS(status); |
status = WEXITSTATUS(status); |
421 |
sig = WTERMSIG(status); |
sig = WTERMSIG(status); |
422 |
status = EXIT_UNCORRECTED; |
status = EXIT_UNCORRECTED; |
423 |
if (sig != SIGINT) { |
if (sig != SIGINT) { |
424 |
printf("Warning... %s %s exited " |
printf("Warning: %s %s terminated " |
425 |
"with signal %d\n", |
"by signal %d\n", |
426 |
inst->prog, inst->device, sig); |
inst->prog, inst->device, sig); |
427 |
status = EXIT_ERROR; |
status = EXIT_ERROR; |
428 |
} |
} |
431 |
inst->prog, inst->device, status); |
inst->prog, inst->device, status); |
432 |
status = EXIT_ERROR; |
status = EXIT_ERROR; |
433 |
} |
} |
|
inst->exit_status = status; |
|
434 |
|
|
435 |
#if DO_PROGRESS_INDICATOR |
#if DO_PROGRESS_INDICATOR |
436 |
if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) { |
if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) { |
459 |
} |
} |
460 |
#endif |
#endif |
461 |
|
|
|
ret_inst: |
|
462 |
if (prev) |
if (prev) |
463 |
prev->next = inst->next; |
prev->next = inst->next; |
464 |
else |
else |
465 |
instance_list = inst->next; |
instance_list = inst->next; |
466 |
if (verbose > 1) |
if (verbose > 1) |
467 |
printf("Finished with %s (exit status %d)\n", |
printf("Finished with %s (exit status %d)\n", |
468 |
inst->device, inst->exit_status); |
inst->device, status); |
469 |
num_running--; |
num_running--; |
470 |
return inst; |
free_instance(inst); |
471 |
|
|
472 |
|
return status; |
473 |
} |
} |
474 |
|
|
|
#define FLAG_WAIT_ALL 0 |
|
|
#define FLAG_WAIT_ATLEAST_ONE 1 |
|
475 |
/* |
/* |
476 |
* Wait until all executing child processes have exited; return the |
* Wait until all executing child processes have exited; return the |
477 |
* logical OR of all of their exit code values. |
* logical OR of all of their exit code values. |
478 |
*/ |
*/ |
479 |
|
#define FLAG_WAIT_ALL 0 |
480 |
|
#define FLAG_WAIT_ATLEAST_ONE WNOHANG |
481 |
static int wait_many(int flags) |
static int wait_many(int flags) |
482 |
{ |
{ |
483 |
struct fsck_instance *inst; |
int exit_status; |
484 |
int global_status = 0; |
int global_status = 0; |
485 |
int wait_flags = 0; |
int wait_flags = 0; |
486 |
|
|
487 |
while ((inst = wait_one(wait_flags))) { |
while ((exit_status = wait_one(wait_flags)) != -1) { |
488 |
global_status |= inst->exit_status; |
global_status |= exit_status; |
489 |
free_instance(inst); |
wait_flags |= flags; |
|
#ifdef RANDOM_DEBUG |
|
|
if (noexecute && (flags & WNOHANG) && !(random() % 3)) |
|
|
break; |
|
|
#endif |
|
|
if (flags & FLAG_WAIT_ATLEAST_ONE) |
|
|
wait_flags = WNOHANG; |
|
490 |
} |
} |
491 |
return global_status; |
return global_status; |
492 |
} |
} |
495 |
* Execute a particular fsck program, and link it into the list of |
* Execute a particular fsck program, and link it into the list of |
496 |
* child processes we are waiting for. |
* child processes we are waiting for. |
497 |
*/ |
*/ |
498 |
static void execute(const char *type, const char *device, const char *mntpt, |
static void execute(const char *type, const char *device, |
499 |
int interactive) |
const char *mntpt /*, int interactive */) |
500 |
{ |
{ |
501 |
char *argv[num_args + 4]; /* see count below: */ |
char *argv[num_args + 4]; /* see count below: */ |
502 |
int argc; |
int argc; |
504 |
struct fsck_instance *inst; |
struct fsck_instance *inst; |
505 |
pid_t pid; |
pid_t pid; |
506 |
|
|
|
inst = xzalloc(sizeof(*inst)); |
|
|
|
|
507 |
argv[0] = xasprintf("fsck.%s", type); /* 1 */ |
argv[0] = xasprintf("fsck.%s", type); /* 1 */ |
508 |
for (i = 0; i < num_args; i++) |
for (i = 0; i < num_args; i++) |
509 |
argv[i+1] = args[i]; /* num_args */ |
argv[i+1] = args[i]; /* num_args */ |
520 |
} |
} |
521 |
#endif |
#endif |
522 |
|
|
523 |
argv[argc++] = xstrdup(device); /* 1 */ |
argv[argc++] = (char*)device; /* 1 */ |
524 |
argv[argc] = NULL; /* 1 */ |
argv[argc] = NULL; /* 1 */ |
525 |
|
|
526 |
if (verbose || noexecute) { |
if (verbose || noexecute) { |
528 |
mntpt ? mntpt : device); |
mntpt ? mntpt : device); |
529 |
for (i = 0; i < argc; i++) |
for (i = 0; i < argc; i++) |
530 |
printf(" %s", argv[i]); |
printf(" %s", argv[i]); |
531 |
puts(""); |
bb_putchar('\n'); |
532 |
} |
} |
533 |
|
|
534 |
/* Fork and execute the correct program. */ |
/* Fork and execute the correct program. */ |
535 |
pid = -1; |
pid = -1; |
536 |
if (!noexecute) { |
if (!noexecute) { |
537 |
pid = fork(); /* TODO: NOMMU friendly way (vfork)? */ |
pid = spawn(argv); |
538 |
if (pid < 0) |
if (pid < 0) |
539 |
bb_perror_msg_and_die("fork"); |
bb_simple_perror_msg(argv[0]); |
|
if (pid == 0) { |
|
|
/* Child */ |
|
|
if (!interactive) { |
|
|
/* NB: e2fsck will complain because of this! |
|
|
* Use "fsck -s" to avoid... */ |
|
|
close(0); |
|
|
} |
|
|
execvp(argv[0], argv); |
|
|
bb_perror_msg_and_die("%s", argv[0]); |
|
|
} |
|
540 |
} |
} |
541 |
|
|
542 |
for (i = num_args+1; i < argc; i++) |
#if DO_PROGRESS_INDICATOR |
543 |
free(argv[i]); |
free(argv[num_args + 1]); |
544 |
|
#endif |
545 |
|
|
546 |
|
/* No child, so don't record an instance */ |
547 |
|
if (pid <= 0) { |
548 |
|
free(argv[0]); |
549 |
|
return; |
550 |
|
} |
551 |
|
|
552 |
|
inst = xzalloc(sizeof(*inst)); |
553 |
inst->pid = pid; |
inst->pid = pid; |
554 |
inst->prog = argv[0]; |
inst->prog = argv[0]; |
|
inst->type = xstrdup(type); |
|
555 |
inst->device = xstrdup(device); |
inst->device = xstrdup(device); |
556 |
inst->base_device = base_device(device); |
inst->base_device = base_device(device); |
557 |
|
#if DO_PROGRESS_INDICATOR |
558 |
inst->start_time = time(NULL); |
inst->start_time = time(NULL); |
559 |
|
#endif |
560 |
|
|
561 |
/* Add to the list of running fsck's. |
/* Add to the list of running fsck's. |
562 |
* (was adding to the end, but adding to the front is simpler...) */ |
* (was adding to the end, but adding to the front is simpler...) */ |
574 |
* If the type isn't specified by the user, then use either the type |
* If the type isn't specified by the user, then use either the type |
575 |
* specified in /etc/fstab, or "auto". |
* specified in /etc/fstab, or "auto". |
576 |
*/ |
*/ |
577 |
static void fsck_device(struct fs_info *fs, int interactive) |
static void fsck_device(struct fs_info *fs /*, int interactive */) |
578 |
{ |
{ |
579 |
const char *type; |
const char *type; |
580 |
|
|
601 |
} |
} |
602 |
|
|
603 |
num_running++; |
num_running++; |
604 |
execute(type, fs->device, fs->mountpt, interactive); |
execute(type, fs->device, fs->mountpt /*, interactive */); |
605 |
} |
} |
606 |
|
|
607 |
/* |
/* |
729 |
return 1; |
return 1; |
730 |
|
|
731 |
/* Are we ignoring this type? */ |
/* Are we ignoring this type? */ |
732 |
if (index_in_str_array(ignored_types, fs->type) >= 0) |
if (index_in_strings(ignored_types, fs->type) >= 0) |
733 |
return 1; |
return 1; |
734 |
|
|
735 |
/* We can and want to check this file system type. */ |
/* We can and want to check this file system type. */ |
753 |
* which should be ignored as done, and resolve any "auto" |
* which should be ignored as done, and resolve any "auto" |
754 |
* filesystem types (done as a side-effect of calling ignore()). |
* filesystem types (done as a side-effect of calling ignore()). |
755 |
*/ |
*/ |
756 |
for (fs = filesys_info; fs; fs = fs->next) { |
for (fs = filesys_info; fs; fs = fs->next) |
757 |
if (ignore(fs)) |
if (ignore(fs)) |
758 |
fs->flags |= FLAG_DONE; |
fs->flags |= FLAG_DONE; |
|
} |
|
759 |
|
|
760 |
/* |
/* |
761 |
* Find and check the root filesystem. |
* Find and check the root filesystem. |
762 |
*/ |
*/ |
763 |
if (!parallel_root) { |
if (!parallel_root) { |
764 |
for (fs = filesys_info; fs; fs = fs->next) { |
for (fs = filesys_info; fs; fs = fs->next) { |
765 |
if (LONE_CHAR(fs->mountpt, '/')) |
if (LONE_CHAR(fs->mountpt, '/')) { |
766 |
|
if (!skip_root && !ignore(fs)) { |
767 |
|
fsck_device(fs /*, 1*/); |
768 |
|
status |= wait_many(FLAG_WAIT_ALL); |
769 |
|
if (status > EXIT_NONDESTRUCT) |
770 |
|
return status; |
771 |
|
} |
772 |
|
fs->flags |= FLAG_DONE; |
773 |
break; |
break; |
|
} |
|
|
if (fs) { |
|
|
if (!skip_root && !ignore(fs)) { |
|
|
fsck_device(fs, 1); |
|
|
status |= wait_many(FLAG_WAIT_ALL); |
|
|
if (status > EXIT_NONDESTRUCT) |
|
|
return status; |
|
774 |
} |
} |
|
fs->flags |= FLAG_DONE; |
|
775 |
} |
} |
776 |
} |
} |
777 |
/* |
/* |
778 |
* This is for the bone-headed user who enters the root |
* This is for the bone-headed user who has root |
779 |
* filesystem twice. Skip root will skip all root entries. |
* filesystem listed twice. |
780 |
|
* "Skip root" will skip _all_ root entries. |
781 |
*/ |
*/ |
782 |
if (skip_root) |
if (skip_root) |
783 |
for (fs = filesys_info; fs; fs = fs->next) |
for (fs = filesys_info; fs; fs = fs->next) |
797 |
continue; |
continue; |
798 |
/* |
/* |
799 |
* If the filesystem's pass number is higher |
* If the filesystem's pass number is higher |
800 |
* than the current pass number, then we don't |
* than the current pass number, then we didn't |
801 |
* do it yet. |
* do it yet. |
802 |
*/ |
*/ |
803 |
if (fs->passno > passno) { |
if (fs->passno > passno) { |
816 |
/* |
/* |
817 |
* Spawn off the fsck process |
* Spawn off the fsck process |
818 |
*/ |
*/ |
819 |
fsck_device(fs, serialize); |
fsck_device(fs /*, serialize*/); |
820 |
fs->flags |= FLAG_DONE; |
fs->flags |= FLAG_DONE; |
821 |
|
|
822 |
/* |
/* |
860 |
int num = 2; |
int num = 2; |
861 |
smallint negate; |
smallint negate; |
862 |
|
|
863 |
if (fs_type) { |
s = fs_type; |
864 |
s = fs_type; |
while ((s = strchr(s, ','))) { |
865 |
while ((s = strchr(s, ','))) { |
num++; |
866 |
num++; |
s++; |
|
s++; |
|
|
} |
|
867 |
} |
} |
868 |
|
|
869 |
fs_type_list = xzalloc(num * sizeof(fs_type_list[0])); |
fs_type_list = xzalloc(num * sizeof(fs_type_list[0])); |
870 |
fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0])); |
fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0])); |
871 |
fs_type_negated = -1; /* not yet known is it negated or not */ |
fs_type_negated = -1; /* not yet known is it negated or not */ |
872 |
|
|
|
if (!fs_type) |
|
|
return; |
|
|
|
|
873 |
num = 0; |
num = 0; |
874 |
s = fs_type; |
s = fs_type; |
875 |
while (1) { |
while (1) { |
907 |
} |
} |
908 |
} |
} |
909 |
|
|
910 |
static void parse_args(int argc, char *argv[]) |
static void parse_args(char **argv) |
911 |
{ |
{ |
912 |
int i, j; |
int i, j; |
913 |
char *arg, *tmp; |
char *arg, *tmp; |
914 |
char *options = NULL; |
char *options; |
915 |
int optpos = 0; |
int optpos; |
916 |
int opts_for_fsck = 0; |
int opts_for_fsck = 0; |
917 |
|
|
918 |
/* in bss, so already zeroed |
/* in bss, so already zeroed |
921 |
instance_list = NULL; |
instance_list = NULL; |
922 |
*/ |
*/ |
923 |
|
|
924 |
/* TODO: getopt32 */ |
for (i = 1; argv[i]; i++) { |
|
for (i = 1; i < argc; i++) { |
|
925 |
arg = argv[i]; |
arg = argv[i]; |
926 |
|
|
927 |
/* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */ |
/* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */ |
929 |
// FIXME: must check that arg is a blkdev, or resolve |
// FIXME: must check that arg is a blkdev, or resolve |
930 |
// "/path", "UUID=xxx" or "LABEL=xxx" into block device name |
// "/path", "UUID=xxx" or "LABEL=xxx" into block device name |
931 |
// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties) |
// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties) |
932 |
devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0])); |
devices = xrealloc_vector(devices, 2, num_devices); |
933 |
devices[num_devices++] = xstrdup(arg); |
devices[num_devices++] = xstrdup(arg); |
934 |
continue; |
continue; |
935 |
} |
} |
936 |
|
|
937 |
if (arg[0] != '-' || opts_for_fsck) { |
if (arg[0] != '-' || opts_for_fsck) { |
938 |
args = xrealloc(args, (num_args+1) * sizeof(args[0])); |
args = xrealloc_vector(args, 2, num_args); |
939 |
args[num_args++] = xstrdup(arg); |
args[num_args++] = xstrdup(arg); |
940 |
continue; |
continue; |
941 |
} |
} |
942 |
|
|
943 |
|
if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */ |
944 |
|
opts_for_fsck = 1; |
945 |
|
continue; |
946 |
|
} |
947 |
|
|
948 |
|
optpos = 0; |
949 |
|
options = NULL; |
950 |
for (j = 1; arg[j]; j++) { |
for (j = 1; arg[j]; j++) { |
|
if (opts_for_fsck) { |
|
|
optpos++; |
|
|
/* one extra for '\0' */ |
|
|
options = xrealloc(options, optpos + 2); |
|
|
options[optpos] = arg[j]; |
|
|
continue; |
|
|
} |
|
951 |
switch (arg[j]) { |
switch (arg[j]) { |
952 |
case 'A': |
case 'A': |
953 |
doall = 1; |
doall = 1; |
960 |
goto next_arg; |
goto next_arg; |
961 |
} |
} |
962 |
/* -C n */ |
/* -C n */ |
963 |
progress_fd = xatoi_u(argv[++i]); |
if (!argv[++i]) bb_show_usage(); |
964 |
|
progress_fd = xatoi_u(argv[i]); |
965 |
goto next_arg; |
goto next_arg; |
966 |
#endif |
#endif |
967 |
case 'V': |
case 'V': |
990 |
bb_show_usage(); |
bb_show_usage(); |
991 |
if (arg[++j]) |
if (arg[++j]) |
992 |
tmp = &arg[j]; |
tmp = &arg[j]; |
993 |
else if (++i < argc) |
else if (argv[++i]) |
994 |
tmp = argv[i]; |
tmp = argv[i]; |
995 |
else |
else |
996 |
bb_show_usage(); |
bb_show_usage(); |
997 |
fstype = xstrdup(tmp); |
fstype = xstrdup(tmp); |
998 |
compile_fs_type(fstype); |
compile_fs_type(fstype); |
999 |
goto next_arg; |
goto next_arg; |
|
case '-': |
|
|
opts_for_fsck++; |
|
|
break; |
|
1000 |
case '?': |
case '?': |
1001 |
bb_show_usage(); |
bb_show_usage(); |
1002 |
break; |
break; |
1012 |
if (optpos) { |
if (optpos) { |
1013 |
options[0] = '-'; |
options[0] = '-'; |
1014 |
options[optpos + 1] = '\0'; |
options[optpos + 1] = '\0'; |
1015 |
args = xrealloc(args, (num_args+1) * sizeof(args[0])); |
args = xrealloc_vector(args, 2, num_args); |
1016 |
args[num_args++] = options; |
args[num_args++] = options; |
|
optpos = 0; |
|
|
options = NULL; |
|
1017 |
} |
} |
1018 |
} |
} |
1019 |
if (getenv("FSCK_FORCE_ALL_PARALLEL")) |
if (getenv("FSCK_FORCE_ALL_PARALLEL")) |
1023 |
max_running = xatoi(tmp); |
max_running = xatoi(tmp); |
1024 |
} |
} |
1025 |
|
|
1026 |
static void signal_cancel(int sig ATTRIBUTE_UNUSED) |
static void signal_cancel(int sig UNUSED_PARAM) |
1027 |
{ |
{ |
1028 |
cancel_requested = 1; |
cancel_requested = 1; |
1029 |
} |
} |
1030 |
|
|
1031 |
int fsck_main(int argc, char *argv[]) |
int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1032 |
|
int fsck_main(int argc UNUSED_PARAM, char **argv) |
1033 |
{ |
{ |
1034 |
int i, status = 0; |
int i, status; |
1035 |
int interactive; |
/*int interactive;*/ |
1036 |
const char *fstab; |
const char *fstab; |
1037 |
struct fs_info *fs; |
struct fs_info *fs; |
|
struct sigaction sa; |
|
1038 |
|
|
1039 |
memset(&sa, 0, sizeof(sa)); |
/* we want wait() to be interruptible */ |
1040 |
sa.sa_handler = signal_cancel; |
signal_no_SA_RESTART_empty_mask(SIGINT, signal_cancel); |
1041 |
sigaction(SIGINT, &sa, 0); |
signal_no_SA_RESTART_empty_mask(SIGTERM, signal_cancel); |
|
sigaction(SIGTERM, &sa, 0); |
|
1042 |
|
|
1043 |
setbuf(stdout, NULL); |
setbuf(stdout, NULL); |
1044 |
|
|
1045 |
parse_args(argc, argv); |
parse_args(argv); |
1046 |
|
|
1047 |
if (!notitle) |
if (!notitle) |
1048 |
puts("fsck (busybox "BB_VER", "BB_BT")"); |
puts("fsck (busybox "BB_VER", "BB_BT")"); |
1054 |
fstab = "/etc/fstab"; |
fstab = "/etc/fstab"; |
1055 |
load_fs_info(fstab); |
load_fs_info(fstab); |
1056 |
|
|
1057 |
interactive = (num_devices == 1) | serialize; |
/*interactive = (num_devices == 1) | serialize;*/ |
1058 |
|
|
1059 |
/* If -A was specified ("check all"), do that! */ |
if (num_devices == 0) |
1060 |
|
/*interactive =*/ serialize = doall = 1; |
1061 |
if (doall) |
if (doall) |
1062 |
return check_all(); |
return check_all(); |
1063 |
|
|
1064 |
if (num_devices == 0) { |
status = 0; |
|
serialize = 1; |
|
|
interactive = 1; |
|
|
return check_all(); |
|
|
} |
|
|
|
|
1065 |
for (i = 0; i < num_devices; i++) { |
for (i = 0; i < num_devices; i++) { |
1066 |
if (cancel_requested) { |
if (cancel_requested) { |
1067 |
kill_all_if_cancel_requested(); |
kill_all_if_cancel_requested(); |
1070 |
|
|
1071 |
fs = lookup(devices[i]); |
fs = lookup(devices[i]); |
1072 |
if (!fs) |
if (!fs) |
1073 |
fs = create_fs_device(devices[i], 0, "auto", 0, -1, -1); |
fs = create_fs_device(devices[i], "", "auto", NULL, -1); |
1074 |
fsck_device(fs, interactive); |
fsck_device(fs /*, interactive */); |
1075 |
|
|
1076 |
if (serialize |
if (serialize |
1077 |
|| (max_running && (num_running >= max_running)) |
|| (max_running && (num_running >= max_running)) |
1078 |
) { |
) { |
1079 |
struct fsck_instance *inst; |
int exit_status = wait_one(0); |
1080 |
|
if (exit_status >= 0) |
1081 |
inst = wait_one(0); |
status |= exit_status; |
|
if (inst) { |
|
|
status |= inst->exit_status; |
|
|
free_instance(inst); |
|
|
} |
|
1082 |
if (verbose > 1) |
if (verbose > 1) |
1083 |
puts("----------------------------------"); |
puts("----------------------------------"); |
1084 |
} |
} |