diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c index 1cbdcb72..4412fe32 100644 --- a/misc/fuse2fs.c +++ b/misc/fuse2fs.c @@ -36,6 +36,8 @@ #include "ext2fs/ext2fs.h" #include "ext2fs/ext2_fs.h" +#include "../version.h" + #ifdef ENABLE_NLS #include #include @@ -303,6 +305,10 @@ struct fuse2fs { unsigned long magic; ext2_filsys fs; pthread_mutex_t bfl; + char *device; + int ro; + int debug; + int no_default_opts; int panic_on_error; int minixdf; int alloc_all_blocks; @@ -3624,49 +3630,100 @@ static int get_random_bytes(void *p, size_t sz) return (size_t) r == sz; } -static void print_help(const char *progname) +enum { + FUSE2FS_VERSION, + FUSE2FS_HELP, + FUSE2FS_HELPFULL, +}; + +#define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v } + +static struct fuse_opt fuse2fs_opts[] = { + FUSE2FS_OPT("ro", ro, 1), + FUSE2FS_OPT("errors=panic", panic_on_error, 1), + FUSE2FS_OPT("minixdf", minixdf, 1), + FUSE2FS_OPT("fuse2fs_debug", debug, 1), + FUSE2FS_OPT("no_default_opts", no_default_opts, 1), + + FUSE_OPT_KEY("-V", FUSE2FS_VERSION), + FUSE_OPT_KEY("--version", FUSE2FS_VERSION), + FUSE_OPT_KEY("-h", FUSE2FS_HELP), + FUSE_OPT_KEY("--help", FUSE2FS_HELP), + FUSE_OPT_KEY("--helpfull", FUSE2FS_HELPFULL), + FUSE_OPT_END +}; + + +static int fuse2fs_opt_proc(void *data, const char *arg, + int key, struct fuse_args *outargs) { - printf(_("Usage: %s dev mntpt [-o options] [fuse_args]\n"), progname); + struct fuse2fs *ff = data; + + switch (key) { + case FUSE_OPT_KEY_NONOPT: + if (!ff->device) { + ff->device = strdup(arg); + return 0; + } + return 1; + case FUSE2FS_HELP: + case FUSE2FS_HELPFULL: + fprintf(stderr, + "usage: %s device/image mountpoint [options]\n" + "\n" + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + " -V --version print version\n" + "\n" + "fuse2fs options:\n" + " -o ro read-only mount\n" + " -o errors=panic dump core on error\n" + " -o minixdf minix-style df\n" + " -o no_default_opts do not include default fuse options\n" + " -o fuse2fs_debug enable fuse2fs debugging\n" + "\n", + outargs->argv[0]); + if (key == FUSE2FS_HELPFULL) { + fuse_opt_add_arg(outargs, "-ho"); + fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL); + } else { + fprintf(stderr, "Try --helpfull to get a list of " + "all flags, including the FUSE options.\n"); + } + exit(1); + + case FUSE2FS_VERSION: + fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION, + E2FSPROGS_DATE); + fuse_opt_add_arg(outargs, "--version"); + fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL); + exit(0); + } + return 1; } int main(int argc, char *argv[]) { + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse2fs fctx; errcode_t err; char *tok, *arg, *logfile; int i; - int readwrite = 1, panic_on_error = 0, minixdf = 0; - struct fuse2fs *ff; char extra_args[BUFSIZ]; int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE; - if (argc < 2) { - print_help(argv[0]); - return 1; + memset(&fctx, 0, sizeof(fctx)); + fctx.magic = FUSE2FS_MAGIC; + + fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc); + if (fctx.device == NULL) { + fprintf(stderr, "Missing ext4 device/image\n"); + fprintf(stderr, "See '%s -h' for usage\n", argv[0]); + exit(1); } - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "--help") == 0) { - print_help(argv[0]); - return 1; - } - } - - for (i = 1; i < argc - 1; i++) { - if (strcmp(argv[i], "-o")) - continue; - arg = argv[i + 1]; - while ((tok = strtok(arg, ","))) { - arg = NULL; - if (!strcmp(tok, "ro")) - readwrite = 0; - else if (!strcmp(tok, "errors=panic")) - panic_on_error = 1; - else if (!strcmp(tok, "minixdf")) - minixdf = 1; - } - } - - if (!readwrite) + if (fctx.ro) printf("%s", _("Mounting read-only.\n")); #ifdef ENABLE_NLS @@ -3678,57 +3735,48 @@ int main(int argc, char *argv[]) #endif add_error_table(&et_ext2_error_table); - ff = calloc(1, sizeof(*ff)); - if (!ff) { - perror("init"); - return 1; - } - ff->magic = FUSE2FS_MAGIC; - ff->panic_on_error = panic_on_error; - ff->minixdf = minixdf; - /* Set up error logging */ logfile = getenv("FUSE2FS_LOGFILE"); if (logfile) { - ff->err_fp = fopen(logfile, "a"); - if (!ff->err_fp) { + fctx.err_fp = fopen(logfile, "a"); + if (!fctx.err_fp) { perror(logfile); goto out_nofs; } } else - ff->err_fp = stderr; + fctx.err_fp = stderr; /* Will we allow users to allocate every last block? */ if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) { printf(_("%s: Allowing users to allocate all blocks. " - "This is dangerous!\n"), argv[1]); - ff->alloc_all_blocks = 1; + "This is dangerous!\n"), fctx.device); + fctx.alloc_all_blocks = 1; } /* Start up the fs (while we still can use stdout) */ ret = 2; - if (readwrite) + if (!fctx.ro) flags |= EXT2_FLAG_RW; - err = ext2fs_open2(argv[1], NULL, flags, 0, 0, unix_io_manager, + err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager, &global_fs); if (err) { - printf(_("%s: %s.\n"), argv[1], error_message(err)); - printf(_("Please run e2fsck -fy %s.\n"), argv[1]); + printf(_("%s: %s.\n"), fctx.device, error_message(err)); + printf(_("Please run e2fsck -fy %s.\n"), fctx.device); goto out_nofs; } - ff->fs = global_fs; - global_fs->priv_data = ff; + fctx.fs = global_fs; + global_fs->priv_data = &fctx; ret = 3; if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) { - if (readwrite) { - printf(_("%s: recovering journal\n"), argv[1]); + if (!fctx.ro) { + printf(_("%s: recovering journal\n"), fctx.device); err = ext2fs_run_ext3_journal(&global_fs); if (err) { - printf(_("%s: %s.\n"), argv[1], + printf(_("%s: %s.\n"), fctx.device, error_message(err)); printf(_("Please run e2fsck -fy %s.\n"), - argv[1]); + fctx.device); goto out; } ext2fs_clear_feature_journal_needs_recovery(global_fs->super); @@ -3740,10 +3788,10 @@ int main(int argc, char *argv[]) } } - if (readwrite) { + if (!fctx.ro) { if (ext2fs_has_feature_journal(global_fs->super)) printf(_("%s: Writing to the journal is not supported.\n"), - argv[1]); + fctx.device); err = ext2fs_read_inode_bitmap(global_fs); if (err) { translate_error(global_fs, 0, err); @@ -3779,19 +3827,27 @@ int main(int argc, char *argv[]) } /* Initialize generation counter */ - get_random_bytes(&ff->next_generation, sizeof(unsigned int)); + get_random_bytes(&fctx.next_generation, sizeof(unsigned int)); - /* Stuff in some fuse parameters of our own */ + /* Set up default fuse parameters */ snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino," - "fsname=%s,attr_timeout=0,allow_other" FUSE_PLATFORM_OPTS, + "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS, argv[1]); - argv[0] = argv[1]; - argv[1] = argv[2]; - argv[2] = extra_args; + if (fctx.no_default_opts == 0) + fuse_opt_add_arg(&args, extra_args); - pthread_mutex_init(&ff->bfl, NULL); - fuse_main(argc, argv, &fs_ops, ff); - pthread_mutex_destroy(&ff->bfl); + if (fctx.debug) { + int i; + + printf("fuse arguments:"); + for (i = 0; i < args.argc; i++) + printf(" '%s'", args.argv[i]); + printf("\n"); + } + + pthread_mutex_init(&fctx.bfl, NULL); + fuse_main(args.argc, args.argv, &fs_ops, &fctx); + pthread_mutex_destroy(&fctx.bfl); ret = 0; out: @@ -3800,7 +3856,6 @@ out: com_err(argv[0], err, "while closing fs"); global_fs = NULL; out_nofs: - free(ff); return ret; }