fuse2fs: improve command-line parsing

Use libfuse's command line parsing, which is much more powerful and
flexible than what we had before, and to allow the user to have more
fine-grained control over FUSE's run-time options.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
debian
Theodore Ts'o 2016-03-12 02:06:14 -05:00
parent 5b7afaf181
commit 69df84967f
1 changed files with 121 additions and 66 deletions

View File

@ -36,6 +36,8 @@
#include "ext2fs/ext2fs.h"
#include "ext2fs/ext2_fs.h"
#include "../version.h"
#ifdef ENABLE_NLS
#include <libintl.h>
#include <locale.h>
@ -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;
}