X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=misc%2Ffsck.c;h=4efe10eca4160fae9544fb9f3d26da94c8bb58d1;hb=4ebce13292f54c96f43dcb1bd1d5b8df5dc8749d;hp=da8586777e2496d1e7ff8bded3943bc3a4333cc2;hpb=993aa11dc8f20122b58332cb49085e190ab3a9e0;p=tools%2Fe2fsprogs.git diff --git a/misc/fsck.c b/misc/fsck.c index da85867..4efe10e 100644 --- a/misc/fsck.c +++ b/misc/fsck.c @@ -7,9 +7,7 @@ * parallel execution. * * Written by Theodore Ts'o, - * - * Usage: fsck [-ACVRNTM] [-s] [-t fstype] [fs-options] device - * + * * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994: * o Changed -t fstype to behave like with mount when -A (all file * systems) or -M (like mount) is specified. @@ -18,7 +16,8 @@ * can be added without changing this front-end. * o -R flag skip root file system. * - * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public @@ -26,9 +25,11 @@ * %End-Header% */ +#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */ + +#include "config.h" #include #include -#include #include #include #include @@ -53,9 +54,12 @@ #if HAVE_MALLOC_H #include #endif +#ifdef HAVE_SIGNAL_H +#include +#endif #include "../version.h" -#include "nls-enable.h" +#include "support/nls-enable.h" #include "fsck.h" #include "blkid/blkid.h" @@ -79,6 +83,8 @@ static const char *really_wanted[] = { "minix", "ext2", "ext3", + "ext4", + "ext4dev", "jfs", "reiserfs", "xiafs", @@ -91,31 +97,32 @@ static const char *really_wanted[] = { /* * Global variables for options */ -char *devices[MAX_DEVICES]; -char *args[MAX_ARGS]; -int num_devices, num_args; - -int verbose = 0; -int doall = 0; -int noexecute = 0; -int serialize = 0; -int skip_root = 0; -int like_mount = 0; -int notitle = 0; -int parallel_root = 0; -int progress = 0; -int force_all_parallel = 0; -int num_running = 0; -int max_running = 0; -volatile int cancel_requested = 0; -int kill_sent = 0; -char *progname; -char *fstype = NULL; -struct fs_info *filesys_info = NULL, *filesys_last = NULL; -struct fsck_instance *instance_list; -const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc"; -char *fsck_path = 0; -blkid_cache cache = NULL; +static char *devices[MAX_DEVICES]; +static char *args[MAX_ARGS]; +static int num_devices, num_args; + +static int verbose = 0; +static int doall = 0; +static int noexecute = 0; +static int serialize = 0; +static int skip_root = 0; +static int ignore_mounted = 0; +static int notitle = 0; +static int parallel_root = 0; +static int progress = 0; +static int progress_fd = 0; +static int force_all_parallel = 0; +static int num_running = 0; +static int max_running = 0; +static volatile int cancel_requested = 0; +static int kill_sent = 0; +static char *progname; +static char *fstype = NULL; +static struct fs_info *filesys_info = NULL, *filesys_last = NULL; +static struct fsck_instance *instance_list; +static const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc"; +static char *fsck_path = 0; +static blkid_cache cache = NULL; static char *string_copy(const char *s) { @@ -129,6 +136,18 @@ static char *string_copy(const char *s) return ret; } +static int string_to_int(const char *s) +{ + long l; + char *p; + + l = strtol(s, &p, 0); + if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX) + return -1; + else + return (int) l; +} + static int ignore(struct fs_info *); static char *skip_over_blank(char *cp) @@ -214,18 +233,15 @@ static void parse_escape(char *word) static void free_instance(struct fsck_instance *i) { - if (i->prog) - free(i->prog); - if (i->device) - free(i->device); - if (i->base_device) - free(i->base_device); + free(i->prog); + free(i->device); + free(i->base_device); free(i); return; } static struct fs_info *create_fs_device(const char *device, const char *mntpnt, - const char *type, const char *opts, + const char *type, const char *opts, int freq, int passno) { struct fs_info *fs; @@ -260,20 +276,17 @@ static int parse_fstab_line(char *line, struct fs_info **ret_fs) *ret_fs = 0; strip_line(line); - if ((cp = strchr(line, '#'))) - *cp = 0; /* Ignore everything after the comment char */ cp = line; device = parse_word(&cp); + if (!device || *device == '#') + return 0; /* Ignore blank lines and comments */ mntpnt = parse_word(&cp); type = parse_word(&cp); opts = parse_word(&cp); freq = parse_word(&cp); passno = parse_word(&cp); - if (!device) - return 0; /* Allow blank lines */ - if (!mntpnt || !type) return -1; @@ -294,9 +307,8 @@ static int parse_fstab_line(char *line, struct fs_info **ret_fs) fs = create_fs_device(device, mntpnt, type ? type : "auto", opts, freq ? atoi(freq) : -1, passno ? atoi(passno) : -1); - if (dev) - free(dev); - + free(dev); + if (!fs) return -1; *ret_fs = fs; @@ -306,7 +318,7 @@ static int parse_fstab_line(char *line, struct fs_info **ret_fs) static void interpret_type(struct fs_info *fs) { char *t; - + if (strcmp(fs->type, "auto") != 0) return; t = blkid_get_tag_value(cache, "TYPE", fs->device); @@ -349,21 +361,22 @@ static void load_fs_info(const char *filename) else old_fstab = 0; } - + fclose(f); - - if (old_fstab) { - fputs(_("\007\007\007" + + if (old_fstab && filesys_info) { + fputs("\007\007\007", stderr); + fputs(_( "WARNING: Your /etc/fstab does not contain the fsck passno\n" " field. I will kludge around things for you, but you\n" " should fix your /etc/fstab file as soon as you can.\n\n"), stderr); - + for (fs = filesys_info; fs; fs = fs->next) { fs->passno = 1; } } } - + /* Lookup filesys in /etc/fstab and return the corresponding entry. */ static struct fs_info *lookup(char *filesys) { @@ -395,8 +408,12 @@ static char *find_fsck(char *type) tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s"); for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) { - sprintf(prog, tpl, s, type); - if (stat(prog, &st) == 0) break; + int len = snprintf(prog, sizeof(prog), tpl, s, type); + + if ((len < 0) || (len >= (int) sizeof(prog))) + continue; + if (stat(prog, &st) == 0) + break; } free(p); return(s ? prog : NULL); @@ -422,28 +439,41 @@ static int progress_active(NOARGS) static int execute(const char *type, const char *device, const char *mntpt, int interactive) { - char *s, *argv[80], prog[80]; - int argc, i; + char *s, *argv[80], prog[256]; + int argc, i, len; struct fsck_instance *inst, *p; pid_t pid; + len = snprintf(prog, sizeof(prog), "fsck.%s", type); + if ((len < 0) || (len >= (int) sizeof(prog))) + return EINVAL; + inst = malloc(sizeof(struct fsck_instance)); if (!inst) return ENOMEM; memset(inst, 0, sizeof(struct fsck_instance)); - sprintf(prog, "fsck.%s", type); argv[0] = string_copy(prog); argc = 1; - + for (i=0; i flags |= FLAG_PROGRESS; + (strcmp(type, "ext3") == 0) || + (strcmp(type, "ext4") == 0) || + (strcmp(type, "ext4dev") == 0)) { + char tmp[80]; + + tmp[0] = 0; + if (!progress_active()) { + snprintf(tmp, 80, "-C%d", progress_fd); + inst->flags |= FLAG_PROGRESS; + } else if (progress_fd) + snprintf(tmp, 80, "-C%d", progress_fd * -1); + if (tmp[0]) + argv[argc++] = string_copy(tmp); } } @@ -453,6 +483,7 @@ static int execute(const char *type, const char *device, const char *mntpt, s = find_fsck(prog); if (s == NULL) { fprintf(stderr, _("fsck: %s: not found\n"), prog); + free(inst); return ENOENT; } @@ -463,24 +494,26 @@ static int execute(const char *type, const char *device, const char *mntpt, printf("%s ", argv[i]); printf("\n"); } - + /* Fork and execute the correct program. */ if (noexecute) pid = -1; else if ((pid = fork()) < 0) { perror("fork"); + free(inst); return errno; } else if (pid == 0) { if (!interactive) close(0); (void) execv(s, argv); perror(argv[0]); + free(inst); exit(EXIT_ERROR); } for (i=0; i < argc; i++) free(argv[i]); - + inst->pid = pid; inst->prog = string_copy(prog); inst->type = string_copy(type); @@ -498,7 +531,7 @@ static int execute(const char *type, const char *device, const char *mntpt, p->next = inst; else instance_list = inst; - + return 0; } @@ -551,7 +584,7 @@ static struct fsck_instance *wait_one(int flags) * (inst and prev are thought to be uninitialized variables) */ inst = prev = NULL; - + do { pid = waitpid(-1, &status, flags); if (cancel_requested && !kill_sent) { @@ -580,7 +613,7 @@ static struct fsck_instance *wait_one(int flags) } } while (!inst); - if (WIFEXITED(status)) + if (WIFEXITED(status)) status = WEXITSTATUS(status); else if (WIFSIGNALED(status)) { sig = WTERMSIG(status); @@ -598,13 +631,16 @@ static struct fsck_instance *wait_one(int flags) status = EXIT_ERROR; } inst->exit_status = status; + inst->flags |= FLAG_DONE; 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")) + strcmp(inst2->type, "ext3") && + strcmp(inst2->type, "ext4") && + strcmp(inst2->type, "ext4dev")) continue; /* * If we've just started the fsck, wait a tiny @@ -662,11 +698,11 @@ static int wait_many(int flags) /* * 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. */ @@ -680,7 +716,7 @@ static void fsck_device(struct fs_info *fs, int interactive) if (strcmp(fs->type, "auto") != 0) type = fs->type; else if (fstype && strncmp(fstype, "no", 2) && - strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && + strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && !strchr(fstype, ',')) type = fstype; else @@ -699,7 +735,7 @@ static void fsck_device(struct fs_info *fs, int interactive) /* * Deal with the fsck -t argument. */ -struct fs_type_compile { +static struct fs_type_compile { char **list; int *type; int negate; @@ -729,7 +765,7 @@ static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) cmp->list = malloc(num * sizeof(char *)); cmp->type = malloc(num * sizeof(int)); if (!cmp->list || !cmp->type) { - fputs(_("Couldn't allocate memory for filesystem types\n"), + fputs(_("Couldn't allocate memory for filesystem types\n"), stderr); exit(EXIT_ERROR); } @@ -739,7 +775,7 @@ static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) if (!fs_type) return; - + list = string_copy(fs_type); num = 0; s = strtok(list, ","); @@ -783,14 +819,14 @@ static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) * This function returns true if a particular option appears in a * comma-delimited options list */ -static int opt_in_list(char *opt, char *optlist) +static int opt_in_list(const 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) { @@ -847,6 +883,16 @@ static int ignore(struct fs_info *fs) if (fs->passno == 0) return 1; + /* + * If this is a bind mount, ignore it. + */ + if (opt_in_list("bind", fs->opts)) { + fprintf(stderr, + _("%s: skipping bad line in /etc/fstab: bind mount with nonzero fsck pass number\n"), + fs->mountpt); + return 1; + } + interpret_type(fs); /* @@ -854,7 +900,7 @@ static int ignore(struct fs_info *fs) * ignore it. */ if (!fs_match(fs, &fs_type_compiled)) return 1; - + /* Are we ignoring this type? */ for(ip = ignored_types; *ip; ip++) if (strcmp(fs->type, *ip) == 0) return 1; @@ -903,7 +949,7 @@ static int device_already_active(char *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) + if (!base) return (instance_list != 0); for (inst = instance_list; inst; inst = inst->next) { if (!inst->base_device || !strcmp(base, inst->base_device)) { @@ -936,7 +982,7 @@ static int check_all(NOARGS) if (ignore(fs)) fs->flags |= FLAG_DONE; } - + /* * Find and check the root filesystem. */ @@ -946,7 +992,8 @@ static int check_all(NOARGS) break; } if (fs) { - if (!skip_root && !ignore(fs)) { + if (!skip_root && !ignore(fs) && + !(ignore_mounted && is_mounted(fs->device))) { fsck_device(fs, 1); status |= wait_many(FLAG_WAIT_ALL); if (status > EXIT_NONDESTRUCT) @@ -957,7 +1004,7 @@ static int check_all(NOARGS) } /* * This is for the bone-headed user who enters the root - * filesystem twice. Skip root will skep all root entries. + * filesystem twice. Skip root will skip all root entries. */ if (skip_root) for (fs = filesys_info; fs; fs = fs->next) @@ -982,6 +1029,10 @@ static int check_all(NOARGS) not_done_yet++; continue; } + if (ignore_mounted && is_mounted(fs->device)) { + fs->flags |= FLAG_DONE; + continue; + } /* * If a filesystem on a particular device has * already been spawned, then we need to defer @@ -1015,7 +1066,7 @@ static int check_all(NOARGS) status |= wait_many(pass_done ? FLAG_WAIT_ALL : FLAG_WAIT_ATLEAST_ONE); if (pass_done) { - if (verbose > 1) + if (verbose > 1) printf("----------------------------------\n"); passno++; } else @@ -1031,7 +1082,7 @@ static int check_all(NOARGS) static void usage(NOARGS) { - fputs(_("Usage: fsck [-ACNPRTV] [-t fstype] [fs-options] [filesys ...]\n"), stderr); + fputs(_("Usage: fsck [-AMNPRTV] [ -C [ fd ] ] [-t fstype] [fs-options] [filesys ...]\n"), stderr); exit(EXIT_USAGE); } @@ -1060,7 +1111,7 @@ static void PRS(int argc, char *argv[]) sigaction(SIGINT, &sa, 0); sigaction(SIGTERM, &sa, 0); #endif - + num_devices = 0; num_args = 0; instance_list = 0; @@ -1124,6 +1175,22 @@ static void PRS(int argc, char *argv[]) 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 (argc > i + 1 && + argv[i + 1][0] != '-') { + progress_fd = string_to_int(argv[i]); + if (progress_fd < 0) + progress_fd = 0; + else { + ++i; + goto next_arg; + } + } break; case 'V': verbose++; @@ -1138,7 +1205,7 @@ static void PRS(int argc, char *argv[]) notitle++; break; case 'M': - like_mount++; + ignore_mounted++; break; case 'P': parallel_root++; @@ -1147,6 +1214,7 @@ static void PRS(int argc, char *argv[]) serialize++; break; case 't': + tmp = 0; if (fstype) usage(); if (arg[j+1]) @@ -1221,13 +1289,17 @@ int main(int argc, char *argv[]) if (oldpath) { fsck_path = malloc (strlen (fsck_prefix_path) + 1 + strlen (oldpath) + 1); + if (!fsck_path) { + fprintf(stderr, "%s: Unable to allocate memory for fsck_path\n", progname); + exit(EXIT_ERROR); + } strcpy (fsck_path, fsck_prefix_path); strcat (fsck_path, ":"); strcat (fsck_path, oldpath); } else { fsck_path = string_copy(fsck_prefix_path); } - + if ((num_devices == 1) || (serialize)) interactive = 1; @@ -1255,6 +1327,8 @@ int main(int argc, char *argv[]) if (!fs) continue; } + if (ignore_mounted && is_mounted(fs->device)) + continue; fsck_device(fs, interactive); if (serialize || (max_running && (num_running >= max_running))) { @@ -1265,7 +1339,7 @@ int main(int argc, char *argv[]) status |= inst->exit_status; free_instance(inst); } - if (verbose > 1) + if (verbose > 1) printf("----------------------------------\n"); } }