📄 fsck.c
字号:
goto ret_inst; } /* * gcc -Wall fails saving throw against stupidity * (inst and prev are thought to be uninitialized variables) */ inst = prev = NULL; do { pid = waitpid(-1, &status, flags); if (cancel_requested && !kill_sent) { kill_all(SIGTERM); kill_sent++; } if ((pid == 0) && (flags & WNOHANG)) return NULL; if (pid < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; if (errno == ECHILD) { bb_error_msg("wait: no more child process?!?"); return NULL; } perror("wait"); continue; } for (prev = 0, inst = instance_list; inst; prev = inst, inst = inst->next) { if (inst->pid == pid) break; } } while (!inst); if (WIFEXITED(status)) status = WEXITSTATUS(status); else if (WIFSIGNALED(status)) { sig = WTERMSIG(status); if (sig == SIGINT) { status = EXIT_UNCORRECTED; } else { printf("Warning... %s for device %s exited " "with signal %d.\n", inst->prog, inst->device, sig); status = EXIT_ERROR; } } else { printf("%s %s: status is %x, should never happen.\n", inst->prog, inst->device, status); status = EXIT_ERROR; } inst->exit_status = status; if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) { for (inst2 = instance_list; inst2; inst2 = inst2->next) { if (inst2->flags & FLAG_DONE) continue; if (strcmp(inst2->type, "ext2") && strcmp(inst2->type, "ext3")) continue; /* * If we've just started the fsck, wait a tiny * bit before sending the kill, to give it * time to set up the signal handler */ if (inst2->start_time < time(0)+2) { if (fork() == 0) { sleep(1); kill(inst2->pid, SIGUSR1); exit(0); } } else kill(inst2->pid, SIGUSR1); inst2->flags |= FLAG_PROGRESS; break; } }ret_inst: if (prev) prev->next = inst->next; else instance_list = inst->next; if (verbose > 1) printf("Finished with %s (exit status %d)\n", inst->device, inst->exit_status); num_running--; return inst;}#define FLAG_WAIT_ALL 0#define FLAG_WAIT_ATLEAST_ONE 1/* * Wait until all executing child processes have exited; return the * logical OR of all of their exit code values. */static int wait_many(int flags){ struct fsck_instance *inst; int global_status = 0; int wait_flags = 0; while ((inst = wait_one(wait_flags))) { global_status |= inst->exit_status; free_instance(inst);#ifdef RANDOM_DEBUG if (noexecute && (flags & WNOHANG) && !(random() % 3)) break;#endif if (flags & FLAG_WAIT_ATLEAST_ONE) wait_flags = WNOHANG; } return global_status;}/* * Run the fsck program on a particular device * * If the type is specified using -t, and it isn't prefixed with "no" * (as in "noext2") and only one filesystem type is specified, then * use that type regardless of what is specified in /etc/fstab. * * If the type isn't specified by the user, then use either the type * specified in /etc/fstab, or DEFAULT_FSTYPE. */static void fsck_device(struct fs_info *fs, int interactive){ const char *type; int retval; interpret_type(fs); if (strcmp(fs->type, "auto") != 0) type = fs->type; else if (fstype && strncmp(fstype, "no", 2) && strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && !strchr(fstype, ',')) type = fstype; else type = DEFAULT_FSTYPE; num_running++; retval = execute(type, fs->device, fs->mountpt, interactive); if (retval) { bb_error_msg("error %d while executing fsck.%s for %s", retval, type, fs->device); num_running--; }}/* * Deal with the fsck -t argument. */struct fs_type_compile { char **list; int *type; int negate;} fs_type_compiled;#define FS_TYPE_NORMAL 0#define FS_TYPE_OPT 1#define FS_TYPE_NEGOPT 2static const char fs_type_syntax_error[] ="Either all or none of the filesystem types passed to -t must be prefixed\n" "with 'no' or '!'.";static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp){ char *cp, *list, *s; int num = 2; int negate, first_negate = 1; if (fs_type) { for (cp=fs_type; *cp; cp++) { if (*cp == ',') num++; } } cmp->list = xzalloc(num * sizeof(char *)); cmp->type = xzalloc(num * sizeof(int)); cmp->negate = 0; if (!fs_type) return; list = string_copy(fs_type); num = 0; s = strtok(list, ","); while(s) { negate = 0; if (strncmp(s, "no", 2) == 0) { s += 2; negate = 1; } else if (*s == '!') { s++; negate = 1; } if (strcmp(s, "loop") == 0) /* loop is really short-hand for opts=loop */ goto loop_special_case; else if (strncmp(s, "opts=", 5) == 0) { s += 5; loop_special_case: cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT; } else { if (first_negate) { cmp->negate = negate; first_negate = 0; } if ((negate && !cmp->negate) || (!negate && cmp->negate)) { bb_error_msg_and_die("%s", fs_type_syntax_error); } } cmp->list[num++] = string_copy(s); s = strtok(NULL, ","); } free(list);}/* * This function returns true if a particular option appears in a * comma-delimited options list */static int opt_in_list(char *opt, char *optlist){ char *list, *s; if (!optlist) return 0; list = string_copy(optlist); s = strtok(list, ","); while(s) { if (strcmp(s, opt) == 0) { free(list); return 1; } s = strtok(NULL, ","); } free(list); return 0;}/* See if the filesystem matches the criteria given by the -t option */static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp){ int n, ret = 0, checked_type = 0; char *cp; if (cmp->list == 0 || cmp->list[0] == 0) return 1; for (n=0; (cp = cmp->list[n]); n++) { switch (cmp->type[n]) { case FS_TYPE_NORMAL: checked_type++; if (strcmp(cp, fs->type) == 0) { ret = 1; } break; case FS_TYPE_NEGOPT: if (opt_in_list(cp, fs->opts)) return 0; break; case FS_TYPE_OPT: if (!opt_in_list(cp, fs->opts)) return 0; break; } } if (checked_type == 0) return 1; return (cmp->negate ? !ret : ret);}/* Check if we should ignore this filesystem. */static int ignore(struct fs_info *fs){ int wanted; char *s; /* * If the pass number is 0, ignore it. */ if (fs->passno == 0) return 1; interpret_type(fs); /* * If a specific fstype is specified, and it doesn't match, * ignore it. */ if (!fs_match(fs, &fs_type_compiled)) return 1; /* Are we ignoring this type? */ if (index_in_str_array(ignored_types, fs->type) >= 0) return 1; /* Do we really really want to check this fs? */ wanted = index_in_str_array(really_wanted, fs->type) >= 0; /* See if the <fsck.fs> program is available. */ s = find_fsck(fs->type); if (s == NULL) { if (wanted) bb_error_msg("cannot check %s: fsck.%s not found", fs->device, fs->type); return 1; } free(s); /* We can and want to check this file system type. */ return 0;}/* * Returns TRUE if a partition on the same disk is already being * checked. */static int device_already_active(char *device){ struct fsck_instance *inst; char *base; if (force_all_parallel) return 0;#ifdef BASE_MD /* Don't check a soft raid disk with any other disk */ if (instance_list && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))) return 1;#endif base = base_device(device); /* * If we don't know the base device, assume that the device is * already active if there are any fsck instances running. */ if (!base) return (instance_list != 0); for (inst = instance_list; inst; inst = inst->next) { if (!inst->base_device || !strcmp(base, inst->base_device)) { free(base); return 1; } } free(base); return 0;}/* Check all file systems, using the /etc/fstab table. */static int check_all(void){ struct fs_info *fs = NULL; int status = EXIT_OK; int not_done_yet = 1; int passno = 1; int pass_done; if (verbose) fputs("Checking all file systems.\n", stdout); /* * Do an initial scan over the filesystem; mark filesystems * which should be ignored as done, and resolve any "auto" * filesystem types (done as a side-effect of calling ignore()). */ for (fs = filesys_info; fs; fs = fs->next) { if (ignore(fs)) fs->flags |= FLAG_DONE; } /* * Find and check the root filesystem. */ if (!parallel_root) { for (fs = filesys_info; fs; fs = fs->next) { if (LONE_CHAR(fs->mountpt, '/')) break; } if (fs) { if (!skip_root && !ignore(fs)) { fsck_device(fs, 1); status |= wait_many(FLAG_WAIT_ALL); if (status > EXIT_NONDESTRUCT) return status; } fs->flags |= FLAG_DONE; } } /* * This is for the bone-headed user who enters the root * filesystem twice. Skip root will skep all root entries. */ if (skip_root) for (fs = filesys_info; fs; fs = fs->next) if (LONE_CHAR(fs->mountpt, '/')) fs->flags |= FLAG_DONE; while (not_done_yet) { not_done_yet = 0; pass_done = 1; for (fs = filesys_info; fs; fs = fs->next) { if (cancel_requested) break; if (fs->flags & FLAG_DONE) continue; /* * If the filesystem's pass number is higher * than the current pass number, then we don't * do it yet. */ if (fs->passno > passno) { not_done_yet++; continue; } /* * If a filesystem on a particular device has * already been spawned, then we need to defer * this to another pass. */ if (device_already_active(fs->device)) { pass_done = 0; continue; } /* * Spawn off the fsck process */ fsck_device(fs, serialize); fs->flags |= FLAG_DONE; /* * Only do one filesystem at a time, or if we * have a limit on the number of fsck's extant * at one time, apply that limit. */ if (serialize || (max_running && (num_running >= max_running))) { pass_done = 0; break; } } if (cancel_requested) break; if (verbose > 1) printf("--waiting-- (pass %d)\n", passno); status |= wait_many(pass_done ? FLAG_WAIT_ALL : FLAG_WAIT_ATLEAST_ONE); if (pass_done) { if (verbose > 1) printf("----------------------------------\n"); passno++; } else not_done_yet++; } if (cancel_requested && !kill_sent) { kill_all(SIGTERM); kill_sent++; } status |= wait_many(FLAG_WAIT_ATLEAST_ONE); return status;}static void signal_cancel(int sig FSCK_ATTR((unused))){ cancel_requested++;}static void PRS(int argc, char **argv){ int i, j; char *arg, *dev, *tmp = 0; char options[128]; int opt = 0; int opts_for_fsck = 0; struct sigaction sa; /* * Set up signal action */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = signal_cancel; sigaction(SIGINT, &sa, 0); sigaction(SIGTERM, &sa, 0); num_devices = 0; num_args = 0; instance_list = 0; for (i=1; i < argc; i++) { arg = argv[i]; if (!arg) continue; if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { if (num_devices >= MAX_DEVICES) { bb_error_msg_and_die("too many devices"); } dev = blkid_get_devname(cache, arg, NULL); if (!dev && strchr(arg, '=')) { /* * Check to see if we failed because * /proc/partitions isn't found. */ if (access("/proc/partitions", R_OK) < 0) { bb_perror_msg_and_die("cannot open /proc/partitions " "(is /proc mounted?)"); } /* * Check to see if this is because * we're not running as root */ if (geteuid()) bb_error_msg_and_die( "must be root to scan for matching filesystems: %s\n", arg); else bb_error_msg_and_die( "cannot find matching filesystem: %s", arg); } devices[num_devices++] = dev ? dev : string_copy(arg); continue; } if (arg[0] != '-' || opts_for_fsck) { if (num_args >= MAX_ARGS) { bb_error_msg_and_die("too many arguments"); } args[num_args++] = string_copy(arg); continue; } for (j=1; arg[j]; j++) { if (opts_for_fsck) { options[++opt] = arg[j]; continue; } switch (arg[j]) { case 'A': doall++; break; case 'C': progress++; if (arg[j+1]) { progress_fd = string_to_int(arg+j+1); if (progress_fd < 0) progress_fd = 0; else goto next_arg; } else if ((i+1) < argc && argv[i+1][0] != '-') { progress_fd = string_to_int(argv[i]); if (progress_fd < 0) progress_fd = 0; else { goto next_arg; i++; } } break; case 'V': verbose++; break; case 'N': noexecute++; break; case 'R': skip_root++; break; case 'T': notitle++; break; case 'M': like_mount++; break; case 'P': parallel_root++; break; case 's': serialize++; break; case 't': tmp = 0; if (fstype) bb_show_usage(); if (arg[j+1]) tmp = arg+j+1; else if ((i+1) < argc) tmp = argv[++i]; else bb_show_usage(); fstype = string_copy(tmp); compile_fs_type(fstype, &fs_type_compiled); goto next_arg; case '-': opts_for_fsck++; break; case '?': bb_show_usage(); break; default: options[++opt] = arg[j]; break; } } next_arg: if (opt) { options[0] = '-'; options[++opt] = '\0'; if (num_args >= MAX_ARGS) { bb_error_msg("too many arguments"); } args[num_args++] = string_copy(options); opt = 0; } } if (getenv("FSCK_FORCE_ALL_PARALLEL")) force_all_parallel++; if ((tmp = getenv("FSCK_MAX_INST"))) max_running = atoi(tmp);}int fsck_main(int argc, char **argv);int fsck_main(int argc, char **argv){ int i, status = 0; int interactive = 0; const char *fstab; struct fs_info *fs; setvbuf(stdout, NULL, _IONBF, BUFSIZ); setvbuf(stderr, NULL, _IONBF, BUFSIZ); blkid_get_cache(&cache, NULL); PRS(argc, argv); if (!notitle) printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); fstab = getenv("FSTAB_FILE"); if (!fstab) fstab = _PATH_MNTTAB; load_fs_info(fstab); fsck_path = e2fs_set_sbin_path(); if ((num_devices == 1) || (serialize)) interactive = 1; /* If -A was specified ("check all"), do that! */ if (doall) return check_all(); if (num_devices == 0) { serialize++; interactive++; return check_all(); } for (i = 0; i < num_devices; i++) { if (cancel_requested) { if (!kill_sent) { kill_all(SIGTERM); kill_sent++; } break; } fs = lookup(devices[i]); if (!fs) { fs = create_fs_device(devices[i], 0, "auto", 0, -1, -1); if (!fs) continue; } fsck_device(fs, interactive); if (serialize || (max_running && (num_running >= max_running))) { struct fsck_instance *inst; inst = wait_one(0); if (inst) { status |= inst->exit_status; free_instance(inst); } if (verbose > 1) printf("----------------------------------\n"); } } status |= wait_many(FLAG_WAIT_ALL); blkid_put_cache(cache); return status;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -