20 |
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, |
21 |
* 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. |
* 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. |
22 |
* |
* |
23 |
* %Begin-Header% |
* Licensed under GPLv2, see file LICENSE in this tarball for details. |
|
* This file may be redistributed under the terms of the GNU Public |
|
|
* License. |
|
|
* %End-Header% |
|
24 |
*/ |
*/ |
25 |
|
|
26 |
/* All filesystem specific hooks have been removed. |
/* All filesystem specific hooks have been removed. |
41 |
* API for fsck.something, NOT ad-hoc hacks in generic fsck. */ |
* API for fsck.something, NOT ad-hoc hacks in generic fsck. */ |
42 |
#define DO_PROGRESS_INDICATOR 0 |
#define DO_PROGRESS_INDICATOR 0 |
43 |
|
|
44 |
|
/* fsck 1.41.4 (27-Jan-2009) manpage says: |
45 |
|
* 0 - No errors |
46 |
|
* 1 - File system errors corrected |
47 |
|
* 2 - System should be rebooted |
48 |
|
* 4 - File system errors left uncorrected |
49 |
|
* 8 - Operational error |
50 |
|
* 16 - Usage or syntax error |
51 |
|
* 32 - Fsck canceled by user request |
52 |
|
* 128 - Shared library error |
53 |
|
*/ |
54 |
#define EXIT_OK 0 |
#define EXIT_OK 0 |
55 |
#define EXIT_NONDESTRUCT 1 |
#define EXIT_NONDESTRUCT 1 |
56 |
#define EXIT_DESTRUCT 2 |
#define EXIT_DESTRUCT 2 |
62 |
/* |
/* |
63 |
* Internal structure for mount table entries. |
* Internal structure for mount table entries. |
64 |
*/ |
*/ |
|
|
|
65 |
struct fs_info { |
struct fs_info { |
66 |
struct fs_info *next; |
struct fs_info *next; |
67 |
char *device; |
char *device; |
112 |
|
|
113 |
#define BASE_MD "/dev/md" |
#define BASE_MD "/dev/md" |
114 |
|
|
|
static char **devices; |
|
115 |
static char **args; |
static char **args; |
|
static int num_devices; |
|
116 |
static int num_args; |
static int num_args; |
117 |
static int verbose; |
static int verbose; |
118 |
|
|
123 |
static uint8_t *fs_type_flag; |
static uint8_t *fs_type_flag; |
124 |
static smallint fs_type_negated; |
static smallint fs_type_negated; |
125 |
|
|
|
static volatile smallint cancel_requested; |
|
|
static smallint doall; |
|
126 |
static smallint noexecute; |
static smallint noexecute; |
127 |
static smallint serialize; |
static smallint serialize; |
128 |
static smallint skip_root; |
static smallint skip_root; |
129 |
/* static smallint like_mount; */ |
/* static smallint like_mount; */ |
|
static smallint notitle; |
|
130 |
static smallint parallel_root; |
static smallint parallel_root; |
131 |
static smallint force_all_parallel; |
static smallint force_all_parallel; |
132 |
|
|
307 |
|
|
308 |
fstab = setmntent(filename, "r"); |
fstab = setmntent(filename, "r"); |
309 |
if (!fstab) { |
if (!fstab) { |
310 |
bb_perror_msg("cannot read %s", filename); |
bb_perror_msg("can't read %s", filename); |
311 |
return; |
return; |
312 |
} |
} |
313 |
|
|
357 |
/* |
/* |
358 |
* Send a signal to all outstanding fsck child processes |
* Send a signal to all outstanding fsck child processes |
359 |
*/ |
*/ |
360 |
static void kill_all_if_cancel_requested(void) |
static void kill_all_if_got_signal(void) |
361 |
{ |
{ |
362 |
static smallint kill_sent; |
static smallint kill_sent; |
363 |
|
|
364 |
struct fsck_instance *inst; |
struct fsck_instance *inst; |
365 |
|
|
366 |
if (!cancel_requested || kill_sent) |
if (!bb_got_signal || kill_sent) |
367 |
return; |
return; |
368 |
|
|
369 |
for (inst = instance_list; inst; inst = inst->next) { |
for (inst = instance_list; inst; inst = inst->next) { |
392 |
|
|
393 |
while (1) { |
while (1) { |
394 |
pid = waitpid(-1, &status, flags); |
pid = waitpid(-1, &status, flags); |
395 |
kill_all_if_cancel_requested(); |
kill_all_if_got_signal(); |
396 |
if (pid == 0) /* flags == WNOHANG and no children exited */ |
if (pid == 0) /* flags == WNOHANG and no children exited */ |
397 |
return -1; |
return -1; |
398 |
if (pid < 0) { |
if (pid < 0) { |
499 |
static void execute(const char *type, const char *device, |
static void execute(const char *type, const char *device, |
500 |
const char *mntpt /*, int interactive */) |
const char *mntpt /*, int interactive */) |
501 |
{ |
{ |
|
char *argv[num_args + 4]; /* see count below: */ |
|
|
int argc; |
|
502 |
int i; |
int i; |
503 |
struct fsck_instance *inst; |
struct fsck_instance *inst; |
504 |
pid_t pid; |
pid_t pid; |
505 |
|
|
506 |
argv[0] = xasprintf("fsck.%s", type); /* 1 */ |
args[0] = xasprintf("fsck.%s", type); |
|
for (i = 0; i < num_args; i++) |
|
|
argv[i+1] = args[i]; /* num_args */ |
|
|
argc = num_args + 1; |
|
507 |
|
|
508 |
#if DO_PROGRESS_INDICATOR |
#if DO_PROGRESS_INDICATOR |
509 |
if (progress && !progress_active()) { |
if (progress && !progress_active()) { |
510 |
if (strcmp(type, "ext2") == 0 |
if (strcmp(type, "ext2") == 0 |
511 |
|| strcmp(type, "ext3") == 0 |
|| strcmp(type, "ext3") == 0 |
512 |
) { |
) { |
513 |
argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */ |
args[XXX] = xasprintf("-C%d", progress_fd); /* 1 */ |
514 |
inst->flags |= FLAG_PROGRESS; |
inst->flags |= FLAG_PROGRESS; |
515 |
} |
} |
516 |
} |
} |
517 |
#endif |
#endif |
518 |
|
|
519 |
argv[argc++] = (char*)device; /* 1 */ |
args[num_args - 2] = (char*)device; |
520 |
argv[argc] = NULL; /* 1 */ |
/* args[num_args - 1] = NULL; - already is */ |
521 |
|
|
522 |
if (verbose || noexecute) { |
if (verbose || noexecute) { |
523 |
printf("[%s (%d) -- %s]", argv[0], num_running, |
printf("[%s (%d) -- %s]", args[0], num_running, |
524 |
mntpt ? mntpt : device); |
mntpt ? mntpt : device); |
525 |
for (i = 0; i < argc; i++) |
for (i = 0; args[i]; i++) |
526 |
printf(" %s", argv[i]); |
printf(" %s", args[i]); |
527 |
bb_putchar('\n'); |
bb_putchar('\n'); |
528 |
} |
} |
529 |
|
|
530 |
/* Fork and execute the correct program. */ |
/* Fork and execute the correct program. */ |
531 |
pid = -1; |
pid = -1; |
532 |
if (!noexecute) { |
if (!noexecute) { |
533 |
pid = spawn(argv); |
pid = spawn(args); |
534 |
if (pid < 0) |
if (pid < 0) |
535 |
bb_simple_perror_msg(argv[0]); |
bb_simple_perror_msg(args[0]); |
536 |
} |
} |
537 |
|
|
538 |
#if DO_PROGRESS_INDICATOR |
#if DO_PROGRESS_INDICATOR |
539 |
free(argv[num_args + 1]); |
free(args[XXX]); |
540 |
#endif |
#endif |
541 |
|
|
542 |
/* No child, so don't record an instance */ |
/* No child, so don't record an instance */ |
543 |
if (pid <= 0) { |
if (pid <= 0) { |
544 |
free(argv[0]); |
free(args[0]); |
545 |
return; |
return; |
546 |
} |
} |
547 |
|
|
548 |
inst = xzalloc(sizeof(*inst)); |
inst = xzalloc(sizeof(*inst)); |
549 |
inst->pid = pid; |
inst->pid = pid; |
550 |
inst->prog = argv[0]; |
inst->prog = args[0]; |
551 |
inst->device = xstrdup(device); |
inst->device = xstrdup(device); |
552 |
inst->base_device = base_device(device); |
inst->base_device = base_device(device); |
553 |
#if DO_PROGRESS_INDICATOR |
#if DO_PROGRESS_INDICATOR |
787 |
pass_done = 1; |
pass_done = 1; |
788 |
|
|
789 |
for (fs = filesys_info; fs; fs = fs->next) { |
for (fs = filesys_info; fs; fs = fs->next) { |
790 |
if (cancel_requested) |
if (bb_got_signal) |
791 |
break; |
break; |
792 |
if (fs->flags & FLAG_DONE) |
if (fs->flags & FLAG_DONE) |
793 |
continue; |
continue; |
827 |
break; |
break; |
828 |
} |
} |
829 |
} |
} |
830 |
if (cancel_requested) |
if (bb_got_signal) |
831 |
break; |
break; |
832 |
if (verbose > 1) |
if (verbose > 1) |
833 |
printf("--waiting-- (pass %d)\n", passno); |
printf("--waiting-- (pass %d)\n", passno); |
840 |
} else |
} else |
841 |
not_done_yet = 1; |
not_done_yet = 1; |
842 |
} |
} |
843 |
kill_all_if_cancel_requested(); |
kill_all_if_got_signal(); |
844 |
status |= wait_many(FLAG_WAIT_ATLEAST_ONE); |
status |= wait_many(FLAG_WAIT_ATLEAST_ONE); |
845 |
return status; |
return status; |
846 |
} |
} |
903 |
} |
} |
904 |
} |
} |
905 |
|
|
906 |
static void parse_args(char **argv) |
static char **new_args(void) |
907 |
{ |
{ |
908 |
int i, j; |
args = xrealloc_vector(args, 2, num_args); |
909 |
char *arg, *tmp; |
return &args[num_args++]; |
910 |
char *options; |
} |
|
int optpos; |
|
|
int opts_for_fsck = 0; |
|
911 |
|
|
912 |
/* in bss, so already zeroed |
int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
913 |
|
int fsck_main(int argc UNUSED_PARAM, char **argv) |
914 |
|
{ |
915 |
|
int i, status; |
916 |
|
/*int interactive;*/ |
917 |
|
struct fs_info *fs; |
918 |
|
const char *fstab; |
919 |
|
char *tmp; |
920 |
|
char **devices; |
921 |
|
int num_devices; |
922 |
|
smallint opts_for_fsck; |
923 |
|
smallint doall; |
924 |
|
smallint notitle; |
925 |
|
|
926 |
|
/* we want wait() to be interruptible */ |
927 |
|
signal_no_SA_RESTART_empty_mask(SIGINT, record_signo); |
928 |
|
signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo); |
929 |
|
|
930 |
|
setbuf(stdout, NULL); |
931 |
|
|
932 |
|
opts_for_fsck = doall = notitle = 0; |
933 |
|
devices = NULL; |
934 |
num_devices = 0; |
num_devices = 0; |
935 |
num_args = 0; |
new_args(); /* args[0] = NULL, will be replaced by fsck.<type> */ |
936 |
instance_list = NULL; |
/* instance_list = NULL; - in bss, so already zeroed */ |
|
*/ |
|
937 |
|
|
938 |
for (i = 1; argv[i]; i++) { |
while (*++argv) { |
939 |
arg = argv[i]; |
int j; |
940 |
|
int optpos; |
941 |
|
char *options; |
942 |
|
char *arg = *argv; |
943 |
|
|
944 |
/* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */ |
/* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */ |
945 |
if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { |
if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { |
947 |
// "/path", "UUID=xxx" or "LABEL=xxx" into block device name |
// "/path", "UUID=xxx" or "LABEL=xxx" into block device name |
948 |
// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties) |
// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties) |
949 |
devices = xrealloc_vector(devices, 2, num_devices); |
devices = xrealloc_vector(devices, 2, num_devices); |
950 |
devices[num_devices++] = xstrdup(arg); |
devices[num_devices++] = arg; |
951 |
continue; |
continue; |
952 |
} |
} |
953 |
|
|
954 |
if (arg[0] != '-' || opts_for_fsck) { |
if (arg[0] != '-' || opts_for_fsck) { |
955 |
args = xrealloc_vector(args, 2, num_args); |
*new_args() = arg; |
|
args[num_args++] = xstrdup(arg); |
|
956 |
continue; |
continue; |
957 |
} |
} |
958 |
|
|
976 |
goto next_arg; |
goto next_arg; |
977 |
} |
} |
978 |
/* -C n */ |
/* -C n */ |
979 |
if (!argv[++i]) bb_show_usage(); |
if (!*++argv) |
980 |
progress_fd = xatoi_u(argv[i]); |
bb_show_usage(); |
981 |
|
progress_fd = xatoi_u(*argv); |
982 |
goto next_arg; |
goto next_arg; |
983 |
#endif |
#endif |
984 |
case 'V': |
case 'V': |
1007 |
bb_show_usage(); |
bb_show_usage(); |
1008 |
if (arg[++j]) |
if (arg[++j]) |
1009 |
tmp = &arg[j]; |
tmp = &arg[j]; |
1010 |
else if (argv[++i]) |
else if (*++argv) |
1011 |
tmp = argv[i]; |
tmp = *argv; |
1012 |
else |
else |
1013 |
bb_show_usage(); |
bb_show_usage(); |
1014 |
fstype = xstrdup(tmp); |
fstype = xstrdup(tmp); |
1029 |
if (optpos) { |
if (optpos) { |
1030 |
options[0] = '-'; |
options[0] = '-'; |
1031 |
options[optpos + 1] = '\0'; |
options[optpos + 1] = '\0'; |
1032 |
args = xrealloc_vector(args, 2, num_args); |
*new_args() = options; |
|
args[num_args++] = options; |
|
1033 |
} |
} |
1034 |
} |
} |
1035 |
if (getenv("FSCK_FORCE_ALL_PARALLEL")) |
if (getenv("FSCK_FORCE_ALL_PARALLEL")) |
1037 |
tmp = getenv("FSCK_MAX_INST"); |
tmp = getenv("FSCK_MAX_INST"); |
1038 |
if (tmp) |
if (tmp) |
1039 |
max_running = xatoi(tmp); |
max_running = xatoi(tmp); |
1040 |
} |
new_args(); /* args[num_args - 2] will be replaced by <device> */ |
1041 |
|
new_args(); /* args[num_args - 1] is the last, NULL element */ |
|
static void signal_cancel(int sig UNUSED_PARAM) |
|
|
{ |
|
|
cancel_requested = 1; |
|
|
} |
|
|
|
|
|
int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
|
|
int fsck_main(int argc UNUSED_PARAM, char **argv) |
|
|
{ |
|
|
int i, status; |
|
|
/*int interactive;*/ |
|
|
const char *fstab; |
|
|
struct fs_info *fs; |
|
|
|
|
|
/* we want wait() to be interruptible */ |
|
|
signal_no_SA_RESTART_empty_mask(SIGINT, signal_cancel); |
|
|
signal_no_SA_RESTART_empty_mask(SIGTERM, signal_cancel); |
|
|
|
|
|
setbuf(stdout, NULL); |
|
|
|
|
|
parse_args(argv); |
|
1042 |
|
|
1043 |
if (!notitle) |
if (!notitle) |
1044 |
puts("fsck (busybox "BB_VER", "BB_BT")"); |
puts("fsck (busybox "BB_VER", "BB_BT")"); |
1059 |
|
|
1060 |
status = 0; |
status = 0; |
1061 |
for (i = 0; i < num_devices; i++) { |
for (i = 0; i < num_devices; i++) { |
1062 |
if (cancel_requested) { |
if (bb_got_signal) { |
1063 |
kill_all_if_cancel_requested(); |
kill_all_if_got_signal(); |
1064 |
break; |
break; |
1065 |
} |
} |
1066 |
|
|