command line options

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

command line options

Patrick Guimond
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi

I've got a patch to bring the command line options back to where they
usualy are specified, that is

  progname [OPTIONS...] mountpoint

It uses argp, which can merge the options with the ones the client of
the library wants.
The main benefit would be to use "mount(8)-style syntax:

  mount_my_fs [-o opt,optb --otheropt]  [source] mountpoint

which would be more intuitive as everybody knows mount(8).

Needless to say, this breaks compatibility with current projects using
fuse, so this change of behavior may not be wanted.
But still, I wanted to know if there was interest for this before doing
the uclibc compat layer as it doesn't have an argp interface.

thx

patg
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2-ecc0.1.6 (GNU/Linux)

iD8DBQFC9ojX0X14v95lmw4RAqMXAJ9KZnOPwqnSw3An+NQHTbNAFoxsQgCferQP
+qMFsUvbk6WRfoSdH+QZ0qE=
=2N41
-----END PGP SIGNATURE-----


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Miklos Szeredi
> I've got a patch to bring the command line options back to where they
> usualy are specified, that is
>
>   progname [OPTIONS...] mountpoint
>

What you propose is interesting, but even more interesting would be to
see the actual interface.  Can you please post the patch for review?

> It uses argp, which can merge the options with the ones the client of
> the library wants.
> The main benefit would be to use "mount(8)-style syntax:
>
>   mount_my_fs [-o opt,optb --otheropt]  [source] mountpoint
>
> which would be more intuitive as everybody knows mount(8).
>
> Needless to say, this breaks compatibility with current projects using
> fuse, so this change of behavior may not be wanted.

It would be nice if we could avoid breaking backward compatibility.

Thanks,
Miklos


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Patrick Guimond
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Miklos Szeredi wrote:

>>I've got a patch to bring the command line options back to where they
>>usualy are specified, that is
>>
>>  progname [OPTIONS...] mountpoint
>>
>>Needless to say, this breaks compatibility with current projects using
>>fuse, so this change of behavior may not be wanted.
>
>
> It would be nice if we could avoid breaking backward compatibility.
The patch avoids breaking binary compatibility, though compatiblity with
programs expecting FUSE options to be after the mountpoint would still
not get the arguments parsed.

This problem could be fixed by parsing arguments twice, once before the
 the mountpoint and after if there are arguments left in the vector.

Also uClibc compability is still lacking.

I think I could fix both, tell me if you interested in the feature.

Thanks,
patg
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2-ecc0.1.6 (GNU/Linux)

iD8DBQFC/Wwg0X14v95lmw4RAtdhAKCyjZBQGxVNS4E+Zd47OeaukJCkRwCdFiaw
sFvTSZE5Vg2zGDeu4ox02dU=
=fH/P
-----END PGP SIGNATURE-----

diff -r -u --new-file /home/patg/origcvs/fuse/example/Makefile.am ./example/Makefile.am
--- /home/patg/origcvs/fuse/example/Makefile.am 2005-07-13 10:07:55.000000000 -0400
+++ ./example/Makefile.am 2005-08-12 23:09:54.000000000 -0400
@@ -1,10 +1,11 @@
 ## Process this file with automake to produce Makefile.in
 
-noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll
+noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll hello_argp
 
 fusexmp_SOURCES = fusexmp.c
 fusexmp_fh_SOURCES = fusexmp_fh.c
 null_SOURCES = null.c
 hello_SOURCES = hello.c
+hello_argp_SOURCES = hello_argp.c
 
 LDADD = ../lib/libfuse.la -lpthread
diff -r -u --new-file /home/patg/origcvs/fuse/example/hello_argp.c ./example/hello_argp.c
--- /home/patg/origcvs/fuse/example/hello_argp.c 1969-12-31 19:00:00.000000000 -0500
+++ ./example/hello_argp.c 2005-08-12 23:09:48.000000000 -0400
@@ -0,0 +1,127 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001-2005  Miklos Szeredi <[hidden email]>
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <argp.h>
+
+static const char *hello_str = "Hello World!\n";
+static const char *hello_path = "/hello";
+
+static int hello_getattr(const char *path, struct stat *stbuf)
+{
+    int res = 0;
+
+    memset(stbuf, 0, sizeof(struct stat));
+    if(strcmp(path, "/") == 0) {
+        stbuf->st_mode = S_IFDIR | 0755;
+        stbuf->st_nlink = 2;
+    }
+    else if(strcmp(path, hello_path) == 0) {
+        stbuf->st_mode = S_IFREG | 0444;
+        stbuf->st_nlink = 1;
+        stbuf->st_size = strlen(hello_str);
+    }
+    else
+        res = -ENOENT;
+
+    return res;
+}
+
+static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                         off_t offset, struct fuse_file_info *fi)
+{
+    (void) offset;
+    (void) fi;
+
+    if(strcmp(path, "/") != 0)
+        return -ENOENT;
+
+    filler(buf, ".", NULL, 0);
+    filler(buf, "..", NULL, 0);
+    filler(buf, hello_path + 1, NULL, 0);
+
+    return 0;
+}
+
+static int hello_open(const char *path, struct fuse_file_info *fi)
+{
+    if(strcmp(path, hello_path) != 0)
+        return -ENOENT;
+
+    if((fi->flags & 3) != O_RDONLY)
+        return -EACCES;
+
+    return 0;
+}
+
+static int hello_read(const char *path, char *buf, size_t size, off_t offset,
+                      struct fuse_file_info *fi)
+{
+    size_t len;
+    (void) fi;
+    if(strcmp(path, hello_path) != 0)
+        return -ENOENT;
+
+    len = strlen(hello_str);
+    if (offset < len) {
+        if (offset + size > len)
+            size = len - offset;
+        memcpy(buf, hello_str + offset, size);
+    } else
+        size = 0;
+
+    return size;
+}
+
+
+static int parse_opt(int key, char *arg, struct argp_state *state)
+{
+    switch (key) {
+ case ARGP_KEY_INIT:
+    state->child_inputs[0] = state->input;
+    break;
+    /* Parse other options */
+    }
+
+    return ARGP_ERR_UNKNOWN;
+}
+
+static struct fuse_operations hello_oper = {
+    .getattr = hello_getattr,
+    .readdir = hello_readdir,
+    .open = hello_open,
+    .read = hello_read,
+};
+
+
+static struct argp hello_argp = {
+    .options    = 0,
+    .parser     = &parse_opt,
+    .args_doc   = "redefined_mountpoint",
+    .doc        = "Redefined documentation string",
+};
+
+int main(int argc, char *argv[])
+{
+    void * fuse_input;
+    struct argp_child children[] =  { fuse_parser(), {} };
+
+    /* Parsing is done simultaneously for our parameters and the FUSE params */
+    hello_argp.children = children;
+    if (argp_parse (&hello_argp, argc, argv, 0, 0, &fuse_input))
+        return 1;
+
+    return fuse_main_parsed (fuse_input, &hello_oper);
+}
+
+
diff -r -u --new-file /home/patg/origcvs/fuse/include/fuse.h ./include/fuse.h
--- /home/patg/origcvs/fuse/include/fuse.h 2005-08-11 11:48:09.000000000 -0400
+++ ./include/fuse.h 2005-08-12 23:09:34.000000000 -0400
@@ -360,6 +360,24 @@
 #define fuse_main(argc, argv, op) \
             fuse_main_real(argc, argv, op, sizeof(*(op)))
 
+typedef void* fuse_parser_input;
+/*
+ * FUSE argp parser fetch
+ *
+ * @return FUSE argp parser, expects a fuse_parser_input pointer as child input
+ */
+struct argp_child fuse_parser ();
+
+/*
+ * Main function for parsed arguments
+ *
+ * @param setup the fuse_parser_input passed to the fuse argp parser
+ * @param op the file system operation
+ * @return 0 on success, nonzero on failure
+ */
+#define  fuse_main_parsed(setup, op) \
+                fuse_main_parsed_real ((setup), (op), sizeof (*(op)))
+
 /* ----------------------------------------------------------- *
  * More detailed API                                           *
  * ----------------------------------------------------------- */
@@ -471,6 +489,8 @@
  */
 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
                    size_t op_size);
+int fuse_main_parsed_real(void * setup, const struct fuse_operations *op,
+                          size_t op_size);
 
 /* ----------------------------------------------------------- *
  * Advanced API for event handling, don't worry about this...  *
diff -r -u --new-file /home/patg/origcvs/fuse/lib/fuse_versionscript ./lib/fuse_versionscript
--- /home/patg/origcvs/fuse/lib/fuse_versionscript 2005-08-05 01:57:25.000000000 -0400
+++ ./lib/fuse_versionscript 2005-08-12 23:09:22.000000000 -0400
@@ -22,12 +22,14 @@
  fuse_main;
  fuse_main_compat1;
  fuse_main_compat2;
+ fuse_main_parsed_real;
  fuse_main_real;
  fuse_mount;
  fuse_mount_compat1;
  fuse_new;
  fuse_new_compat1;
  fuse_new_compat2;
+ fuse_parser;
  fuse_process_cmd;
  fuse_read_cmd;
  fuse_reply_err;
diff -r -u --new-file /home/patg/origcvs/fuse/lib/helper.c ./lib/helper.c
--- /home/patg/origcvs/fuse/lib/helper.c 2005-08-03 05:11:05.000000000 -0400
+++ ./lib/helper.c 2005-08-12 23:09:15.000000000 -0400
@@ -15,52 +15,168 @@
 #include <string.h>
 #include <limits.h>
 #include <signal.h>
+#include <argp.h>
+
 
 struct fuse *fuse_new_common(int fd, const char *opts,
                              const struct fuse_operations *op,
                              size_t op_size, int compat);
 
+static int opt_member(const char *opts, const char *opt);
+
+static int add_options(char **lib_optp, char **kernel_optp, const char *opts);
+
+
 static struct fuse *fuse_instance;
 
-static void usage(const char *progname)
+static
+struct argp_option fuse_options[] = {
+    { 0,  0,  0, 0, "FUSE Options:" },
+    { 0, 'v', 0, 0, "enable debug output (implies -f)" },
+    { 0, 'f', 0, 0, "foreground operation" },
+    { 0, 's', 0, 0, "disable multithreaded operation" },
+    { 0, 'r', 0, 0, "mount read only (equivalent to '-o ro')" },
+    { 0, 'o', "opt[,opt...]", 0, "mount options" },
+    /* For backward compatibility */
+    { 0, 'h', 0, OPTION_HIDDEN },
+
+    { 0,  0,  0, 0, "Mount options:" },
+    { "default_permissions", 0, 0, OPTION_DOC , "enable permission checking"},
+    { "allow_other",  0, 0, OPTION_DOC, "allow access to other users" },
+    { "allow_root",   0, 0, OPTION_DOC, "allow access to root" },
+    { "kernel_cache", 0, 0, OPTION_DOC, "cache files in kernel" },
+    { "large_read",   0, 0, OPTION_DOC, "issue large read requests (2.4 only)"},
+    { "direct_io",    0, 0, OPTION_DOC, "use direct I/O" },
+    { "max_read=N",   0, 0, OPTION_DOC, "set maximum size of read requests" },
+    { "hard_remove",  0, 0, OPTION_DOC, "immediate removal (don't hide files)"},
+    { "debug",        0, 0, OPTION_DOC, "enable debug output" },
+    { "fsname=NAME",  0, 0, OPTION_DOC, "set filesystem name in mtab" },
+    { "use_ino",      0, 0, OPTION_DOC, "let filesystem set inode numbers" },
+    { "readdir_ino",  0, 0, OPTION_DOC, "try to fill in d_ino in readdir" },
+    { "nonempty",     0, 0, OPTION_DOC, "allow mounts over non-empty file/dir"},
+    { "umask=N",      0, 0, OPTION_DOC, "set file permissions (octal)" },
+    { "uid=N",        0, 0, OPTION_DOC, "set file owner" },
+    { "gid=N",        0, 0, OPTION_DOC, "set file group" },
+    { 0 }
+};
+
+struct setup_state {
+    char    *kernel_opts;
+    char    *lib_opts;
+    char    *mountpoint;
+    int     multithreaded;
+    int     background;
+};
+
+
+static int parse_opt(int key, char *arg, struct argp_state *state)
 {
-    if (progname)
-        fprintf(stderr,
-                "usage: %s mountpoint [FUSE options]\n\n", progname);
-
-    fprintf(stderr,
-            "FUSE options:\n"
-            "    -d                     enable debug output (implies -f)\n"
-            "    -f                     foreground operation\n"
-            "    -s                     disable multithreaded operation\n"
-            "    -r                     mount read only (equivalent to '-o ro')\n"
-            "    -o opt,[opt...]        mount options\n"
-            "    -h                     print help\n"
-            "\n"
-            "Mount options:\n"
-            "    default_permissions    enable permission checking\n"
-            "    allow_other            allow access to other users\n"
-            "    allow_root             allow access to root\n"
-            "    kernel_cache           cache files in kernel\n"
-            "    large_read             issue large read requests (2.4 only)\n"
-            "    direct_io              use direct I/O\n"
-            "    max_read=N             set maximum size of read requests\n"
-            "    hard_remove            immediate removal (don't hide files)\n"
-            "    debug                  enable debug output\n"
-            "    fsname=NAME            set filesystem name in mtab\n"
-            "    use_ino                let filesystem set inode numbers\n"
-            "    readdir_ino            try to fill in d_ino in readdir\n"
-            "    nonempty               allow mounts over non-empty file/dir\n"
-            "    umask=M                set file permissions (octal)\n"
-            "    uid=N                  set file owner\n"
-            "    gid=N                  set file group\n"
-            );
+    int res;
+    struct setup_state * setup = *((struct setup_state**)state->input);
+
+    switch (key) {
+        case ARGP_KEY_INIT:
+            setup = malloc (sizeof (struct setup_state));
+            setup->kernel_opts  = NULL;
+            setup->lib_opts     = NULL;
+            setup->mountpoint   = NULL;
+            setup->multithreaded= 1;
+            setup->background   = 1;
+            *((struct setup_state**)state->input) = setup;
+            return 0;
+
+        case ARGP_KEY_END:
+            /* Need to assign the filesystem name a default */
+            if (!opt_member(setup->lib_opts, "fsname")) {
+                char *fsname_opt;
+                int namelen = strlen (state->name);
+
+                fsname_opt = alloca (namelen + 8);
+                memcpy (fsname_opt, "fsname=", 7);
+                memcpy (fsname_opt+7, state->name, namelen);
+                fsname_opt[namelen+7] = 0;
+
+                res = add_options(&setup->lib_opts, &setup->kernel_opts,
+                                  fsname_opt);
+                if (res == -1)
+                    return -EINVAL;
+            }
+
+            /* Fallback */
+        case ARGP_NO_ARGS:
+            if (!setup->mountpoint) {
+                fprintf(stderr, "FUSE: missing mountpoint\n\n");
+                /* This call never returns */
+                argp_usage (state);
+            }
+
+            return 0;
+
+        case ARGP_KEY_ERROR:
+            free(setup->kernel_opts);
+            free(setup->lib_opts);
+            free(setup->mountpoint);
+    free(setup);
+            return 0;
+
+        case ARGP_KEY_ARG:
+            if (setup->mountpoint)
+               break;
+
+            setup->mountpoint = strdup (arg);
+            if (setup->mountpoint == NULL) {
+                fputs ("FUSE: memory allocation failed\n", stderr);
+                return -ENOMEM;
+            }
+            return 0;
+
+        case 'o':
+            res = add_options(&setup->lib_opts, &setup->kernel_opts, arg);
+            if (res == -1)
+                return -EINVAL;
+            return 0;
+
+        case 'd':
+            res = add_options(&setup->lib_opts, &setup->kernel_opts, "debug");
+            if (res == -1)
+                return -EINVAL;
+            return 0;
+
+        case 'r':
+            res = add_options(&setup->lib_opts, &setup->kernel_opts, "ro");
+            if (res == -1)
+                return -EINVAL;
+            return 0;
+
+        case 'f':
+            setup->background = 0;
+            break;
+
+        case 's':
+            setup->multithreaded = 0;
+            break;
+
+        case 'h':
+            /* This call never returns */
+            argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP);
+    }
+
+    return ARGP_ERR_UNKNOWN;
 }
 
-static void invalid_option(const char *argv[], int argctr)
+
+static struct argp fuse_argp = {
+    .options    = fuse_options,
+    .parser     = &parse_opt,
+    .args_doc   = "mountpoint",
+    .doc        = "Mounts the filesystem at <mountpoint>"
+};
+
+static struct argp_child fuse_argp_child = { &fuse_argp, 0, "", 0 };
+
+struct argp_child  fuse_parser()
 {
-    fprintf(stderr, "fuse: invalid option: %s\n\n", argv[argctr]);
-    fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
+    return fuse_argp_child;
 }
 
 static void exit_handler(int sig)
@@ -177,134 +293,19 @@
     return 0;
 }
 
-static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts,
-                              char **lib_opts, char **mountpoint,
-                              int *multithreaded, int *background)
+static void fuse_parse_cmdline(struct setup_state ** setup,
+           int argc, char *argv[])
 {
-    int res;
-    int argctr;
-    const char *basename;
-    char *fsname_opt;
-
-    *kernel_opts = NULL;
-    *lib_opts = NULL;
-    *mountpoint = NULL;
-    *multithreaded = 1;
-    *background = 1;
-
-    basename = strrchr(argv[0], '/');
-    if (basename == NULL)
-        basename = argv[0];
-    else if (basename[1] != '\0')
-        basename++;
-
-    fsname_opt = (char *) malloc(strlen(basename) + 64);
-    if (fsname_opt == NULL) {
-        fprintf(stderr, "fuse: memory allocation failed\n");
-        return -1;
-    }
-    sprintf(fsname_opt, "fsname=%s", basename);
-    res = add_options(lib_opts, kernel_opts, fsname_opt);
-    free(fsname_opt);
-    if (res == -1)
-        goto err;
-
-    for (argctr = 1; argctr < argc; argctr ++) {
-        if (argv[argctr][0] == '-') {
-            if (strlen(argv[argctr]) == 2)
-                switch (argv[argctr][1]) {
-                case 'o':
-                    if (argctr + 1 == argc || argv[argctr+1][0] == '-') {
-                        fprintf(stderr, "missing option after -o\n");
-                        fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-                        goto err;
-                    }
-                    argctr ++;
-                    res = add_options(lib_opts, kernel_opts, argv[argctr]);
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'd':
-                    res = add_options(lib_opts, kernel_opts, "debug");
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'r':
-                    res = add_options(lib_opts, kernel_opts, "ro");
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'f':
-                    *background = 0;
-                    break;
-
-                case 's':
-                    *multithreaded = 0;
-                    break;
-
-                case 'h':
-                    usage(argv[0]);
-                    goto err;
-
-                default:
-                    invalid_option(argv, argctr);
-                    goto err;
-                }
-            else {
-                if (argv[argctr][1] == 'o') {
-                    res = add_options(lib_opts, kernel_opts, &argv[argctr][2]);
-                    if (res == -1)
-                        goto err;
-                } else if(strcmp(argv[argctr], "-ho") == 0) {
-                    usage(NULL);
-                    goto err;
-                } else {
-                    invalid_option(argv, argctr);
-                    goto err;
-                }
-            }
-        } else if (*mountpoint == NULL) {
-            *mountpoint = strdup(argv[argctr]);
-            if (*mountpoint == NULL) {
-                fprintf(stderr, "fuse: memory allocation failed\n");
-                goto err;
-            }
-        }
-        else {
-            invalid_option(argv, argctr);
-            goto err;
-        }
-    }
-
-    if (*mountpoint == NULL) {
-        fprintf(stderr, "missing mountpoint\n");
-        fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-        goto err;
-    }
-    return 0;
-
- err:
-    free(*kernel_opts);
-    free(*lib_opts);
-    free(*mountpoint);
-    return -1;
+    argp_parse (&fuse_argp, argc, argv, 0, 0, setup);
 }
 
-static struct fuse *fuse_setup_common(int argc, char *argv[],
+static struct fuse *fuse_setup_common(struct setup_state * setup,
                                       const struct fuse_operations *op,
                                       size_t op_size,
-                                      char **mountpoint,
-                                      int *multithreaded,
                                       int *fd,
                                       int compat)
 {
     struct fuse *fuse;
-    int background;
-    char *kernel_opts;
-    char *lib_opts;
     int res;
 
     if (fuse_instance != NULL) {
@@ -312,21 +313,15 @@
         return NULL;
     }
 
-    res = fuse_parse_cmdline(argc, (const char **) argv, &kernel_opts,
-                             &lib_opts, mountpoint, multithreaded,
-                             &background);
-    if (res == -1)
-        return NULL;
-
-    *fd = fuse_mount(*mountpoint, kernel_opts);
+    *fd = fuse_mount(setup->mountpoint, setup->kernel_opts);
     if (*fd == -1)
         goto err_free;
 
-    fuse = fuse_new_common(*fd, lib_opts, op, op_size, compat);
+    fuse = fuse_new_common(*fd, setup->lib_opts, op, op_size, compat);
     if (fuse == NULL)
         goto err_unmount;
 
-    if (background && !opt_member(lib_opts, "debug")) {
+    if (setup->background && !opt_member(setup->lib_opts, "debug")) {
         res = daemon(0, 0);
         if (res == -1) {
             perror("fuse: failed to daemonize program\n");
@@ -339,38 +334,60 @@
         goto err_destroy;
 
     fuse_instance = fuse;
-    free(kernel_opts);
-    free(lib_opts);
+    free(setup->kernel_opts);
+    free(setup->lib_opts);
     return fuse;
 
  err_destroy:
     fuse_destroy(fuse);
  err_unmount:
-    fuse_unmount(*mountpoint);
+    fuse_unmount(setup->mountpoint);
  err_free:
-    free(kernel_opts);
-    free(lib_opts);
-    free(*mountpoint);
+    free(setup->kernel_opts);
+    free(setup->lib_opts);
+    free(setup->mountpoint);
+    free(setup);
     return NULL;
 }
 
+
+struct fuse *fuse_setup_parse (int argc, char *argv[],
+       const struct fuse_operations *op,
+       size_t op_size, char **mountpoint,
+       int *multithreaded, int *fd, int compat)
+{
+    struct fuse * fuse;
+    struct setup_state *setup;
+
+    fuse_parse_cmdline (&setup, argc, argv);
+
+    *mountpoint   = setup->mountpoint;
+    *multithreaded = setup->multithreaded;
+
+    fuse = fuse_setup_common (setup, op, op_size, fd, compat);
+    free (setup);
+
+    return fuse;
+}
+
 struct fuse *fuse_setup(int argc, char *argv[],
                           const struct fuse_operations *op,
                           size_t op_size, char **mountpoint,
                           int *multithreaded, int *fd)
 {
-    return fuse_setup_common(argc, argv, op, op_size, mountpoint,
+    return fuse_setup_parse (argc, argv, op, op_size, mountpoint,
                              multithreaded, fd, 0);
 }
 
+
 struct fuse *fuse_setup_compat2(int argc, char *argv[],
                                  const struct fuse_operations_compat2 *op,
                                  char **mountpoint, int *multithreaded,
                                  int *fd)
 {
-    return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
-                             sizeof(struct fuse_operations_compat2),
-                             mountpoint, multithreaded, fd, 21);
+    return fuse_setup_parse (argc, argv, (struct fuse_operations *) op,
+     sizeof(struct fuse_operations_compat2),
+     mountpoint, multithreaded, fd, 21);
 }
 
 void fuse_teardown(struct fuse *fuse, int fd, char *mountpoint)
@@ -386,37 +403,53 @@
     free(mountpoint);
 }
 
-static int fuse_main_common(int argc, char *argv[],
+
+static int fuse_main_common(struct setup_state * setup,
                             const struct fuse_operations *op, size_t op_size,
                             int compat)
 {
     struct fuse *fuse;
-    char *mountpoint;
-    int multithreaded;
     int res;
     int fd;
 
-    fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
-                             &multithreaded, &fd, compat);
+    fuse = fuse_setup_common(setup, op, op_size, &fd, compat);
     if (fuse == NULL)
         return 1;
 
-    if (multithreaded)
+    if (setup->multithreaded)
         res = fuse_loop_mt(fuse);
     else
         res = fuse_loop(fuse);
 
-    fuse_teardown(fuse, fd, mountpoint);
+    fuse_teardown (fuse, fd, setup->mountpoint);
+    free (setup);
     if (res == -1)
         return 1;
 
     return 0;
 }
 
+
+static int fuse_main_parse (int argc, char *argv[],
+                            const struct fuse_operations *op, size_t op_size,
+                            int compat)
+{
+    struct setup_state * setup;
+    fuse_parse_cmdline (&setup, argc, argv);
+
+    return fuse_main_common (setup, op, op_size, compat);
+}
+
 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
                    size_t op_size)
 {
-    return fuse_main_common(argc, argv, op, op_size, 0);
+    return fuse_main_parse (argc, argv, op, op_size, 0);
+}
+
+int fuse_main_parsed_real (void * input, const struct fuse_operations *op,
+   size_t op_size)
+{
+    return fuse_main_common (input, op, op_size, 0);
 }
 
 #undef fuse_main
@@ -429,14 +462,14 @@
 void fuse_main_compat1(int argc, char *argv[],
                       const struct fuse_operations_compat1 *op)
 {
-    fuse_main_common(argc, argv, (struct fuse_operations *) op,
+    fuse_main_parse (argc, argv, (struct fuse_operations *) op,
                      sizeof(struct fuse_operations_compat1), 11);
 }
 
 int fuse_main_compat2(int argc, char *argv[],
                       const struct fuse_operations_compat2 *op)
 {
-    return fuse_main_common(argc, argv, (struct fuse_operations *) op,
+    return fuse_main_parse (argc, argv, (struct fuse_operations *) op,
                             sizeof(struct fuse_operations_compat2), 21);
 }
 
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Miklos Szeredi
> The patch avoids breaking binary compatibility, though compatiblity with
> programs expecting FUSE options to be after the mountpoint would still
> not get the arguments parsed.
>
> This problem could be fixed by parsing arguments twice, once before the
>  the mountpoint and after if there are arguments left in the vector.

Why does it need to be parsed twice?  Options and non-options
(mountpoint, mount source) are easily distinguishable by the first
charater being '-' or not, or by the special '--' option.

> Also uClibc compability is still lacking.
>
> I think I could fix both, tell me if you interested in the feature.

Probably yes.  I still have to study the argp interface, but it seems
like a nice way to handle option parsing by several entities within a
single program.

Thanks,
Miklos


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Patrick Guimond
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Miklos Szeredi wrote:

>>The patch avoids breaking binary compatibility, though compatiblity with
>>programs expecting FUSE options to be after the mountpoint would still
>>not get the arguments parsed.
>>
>>This problem could be fixed by parsing arguments twice, once before the
>> the mountpoint and after if there are arguments left in the vector.
>
>
> Why does it need to be parsed twice?  Options and non-options
> (mountpoint, mount source) are easily distinguishable by the first
> charater being '-' or not, or by the special '--' option.
>
Your're right, sorry about that.


I have (not completely) fixed uClibc compatibility. It falls back to
getopt_long for parsing.

Still, getopt_long is a GNU extension of SUSv3, which can be removed
from uClibc at compile time. Although it is enabled by default in the
official uClibc distribution, those who disable it woundn't be able to
compile FUSE.

This could be fixed by using the SUSv3 version of getopt. This shouldn't
be a problem, unless users of the library begin to use long options.
It just depends on the desired level of portability. Tell me if you want
to fallback to SUSv3 getopt.


Also, the major current problem is that the argp interface is completely
disabled when using uClibc, meaning its users would have to be sure
nobody would use their filesystem with uClibc.
It could be possible to reimplement the argp behavior in the helper,
although this would at least double the size of the module. The two
other options I can think of are ignoring the issue and not including
the argp parser.
Could you give me your opinion on this.


Thanks,
patg

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2-ecc0.1.6 (GNU/Linux)

iD8DBQFC/m2Y0X14v95lmw4RAirKAJ9V0mxOJjHO0cgSnW6e+fRmYT+RgQCcCqJi
P5e0dObP6Wk14GO7T2i9sPI=
=NXjp
-----END PGP SIGNATURE-----

diff --new-file -u -r /home/patg/origcvs/fuse/example/Makefile.am ./example/Makefile.am
--- /home/patg/origcvs/fuse/example/Makefile.am 2005-07-13 10:07:55.000000000 -0400
+++ ./example/Makefile.am 2005-08-13 17:15:49.000000000 -0400
@@ -1,10 +1,11 @@
 ## Process this file with automake to produce Makefile.in
 
-noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll
+noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll hello_argp
 
 fusexmp_SOURCES = fusexmp.c
 fusexmp_fh_SOURCES = fusexmp_fh.c
 null_SOURCES = null.c
 hello_SOURCES = hello.c
+hello_argp_SOURCES = hello_argp.c
 
 LDADD = ../lib/libfuse.la -lpthread
diff --new-file -u -r /home/patg/origcvs/fuse/example/hello_argp.c ./example/hello_argp.c
--- /home/patg/origcvs/fuse/example/hello_argp.c 1969-12-31 19:00:00.000000000 -0500
+++ ./example/hello_argp.c 2005-08-13 17:15:56.000000000 -0400
@@ -0,0 +1,134 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001-2005  Miklos Szeredi <[hidden email]>
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+
+static const char *hello_str = "Hello World!\n";
+static const char *hello_path = "/hello";
+
+static int hello_getattr(const char *path, struct stat *stbuf)
+{
+    int res = 0;
+
+    memset(stbuf, 0, sizeof(struct stat));
+    if(strcmp(path, "/") == 0) {
+        stbuf->st_mode = S_IFDIR | 0755;
+        stbuf->st_nlink = 2;
+    }
+    else if(strcmp(path, hello_path) == 0) {
+        stbuf->st_mode = S_IFREG | 0444;
+        stbuf->st_nlink = 1;
+        stbuf->st_size = strlen(hello_str);
+    }
+    else
+        res = -ENOENT;
+
+    return res;
+}
+
+static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                         off_t offset, struct fuse_file_info *fi)
+{
+    (void) offset;
+    (void) fi;
+
+    if(strcmp(path, "/") != 0)
+        return -ENOENT;
+
+    filler(buf, ".", NULL, 0);
+    filler(buf, "..", NULL, 0);
+    filler(buf, hello_path + 1, NULL, 0);
+
+    return 0;
+}
+
+static int hello_open(const char *path, struct fuse_file_info *fi)
+{
+    if(strcmp(path, hello_path) != 0)
+        return -ENOENT;
+
+    if((fi->flags & 3) != O_RDONLY)
+        return -EACCES;
+
+    return 0;
+}
+
+static int hello_read(const char *path, char *buf, size_t size, off_t offset,
+                      struct fuse_file_info *fi)
+{
+    size_t len;
+    (void) fi;
+    if(strcmp(path, hello_path) != 0)
+        return -ENOENT;
+
+    len = strlen(hello_str);
+    if (offset < len) {
+        if (offset + size > len)
+            size = len - offset;
+        memcpy(buf, hello_str + offset, size);
+    } else
+        size = 0;
+
+    return size;
+}
+
+
+
+
+static struct fuse_operations hello_oper = {
+    .getattr = hello_getattr,
+    .readdir = hello_readdir,
+    .open = hello_open,
+    .read = hello_read,
+};
+
+
+#ifndef USE_UCLIBC
+static int parse_opt(int key, char *arg, struct argp_state *state)
+{
+    switch (key) {
+ case ARGP_KEY_INIT:
+    state->child_inputs[0] = state->input;
+    break;
+    /* Parse other options */
+    }
+
+    return ARGP_ERR_UNKNOWN;
+}
+
+static struct argp hello_argp = {
+    .options    = 0,
+    .parser     = &parse_opt,
+    .args_doc   = "added_arg",
+    .doc        = "Redefined documentation string",
+};
+#endif
+
+int main(int argc, char *argv[])
+{
+#ifdef USE_UCLIBC
+    return fuse_main(argc, argv, &hello_oper);
+#else
+    void * fuse_input;
+    struct argp_child children[] =  { fuse_parser(), {} };
+
+    /* Parsing is done simultaneously for our parameters and the FUSE params */
+    hello_argp.children = children;
+    if (argp_parse (&hello_argp, argc, argv, 0, 0, &fuse_input))
+        return 1;
+
+    return fuse_main_parsed (fuse_input, &hello_oper);
+#endif
+}
+
+
diff --new-file -u -r /home/patg/origcvs/fuse/include/fuse.h ./include/fuse.h
--- /home/patg/origcvs/fuse/include/fuse.h 2005-08-11 11:48:09.000000000 -0400
+++ ./include/fuse.h 2005-08-13 17:16:18.000000000 -0400
@@ -22,6 +22,9 @@
 #include <sys/stat.h>
 #include <sys/statfs.h>
 #include <utime.h>
+#ifndef USE_UCLIBC
+#include <argp.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -360,6 +363,26 @@
 #define fuse_main(argc, argv, op) \
             fuse_main_real(argc, argv, op, sizeof(*(op)))
 
+#ifndef USE_UCLIBC
+typedef void* fuse_parser_input;
+/*
+ * FUSE argp parser fetch
+ *
+ * @return FUSE argp parser, expects a fuse_parser_input pointer as child input
+ */
+struct argp_child fuse_parser ();
+
+/*
+ * Main function for parsed arguments
+ *
+ * @param setup the fuse_parser_input passed to the fuse argp parser
+ * @param op the file system operation
+ * @return 0 on success, nonzero on failure
+ */
+#define  fuse_main_parsed(setup, op) \
+                fuse_main_parsed_real ((setup), (op), sizeof (*(op)))
+#endif
+
 /* ----------------------------------------------------------- *
  * More detailed API                                           *
  * ----------------------------------------------------------- */
@@ -471,6 +494,8 @@
  */
 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
                    size_t op_size);
+int fuse_main_parsed_real(void * setup, const struct fuse_operations *op,
+                          size_t op_size);
 
 /* ----------------------------------------------------------- *
  * Advanced API for event handling, don't worry about this...  *
diff --new-file -u -r /home/patg/origcvs/fuse/lib/fuse_versionscript ./lib/fuse_versionscript
--- /home/patg/origcvs/fuse/lib/fuse_versionscript 2005-08-05 01:57:25.000000000 -0400
+++ ./lib/fuse_versionscript 2005-08-13 17:15:39.000000000 -0400
@@ -22,12 +22,14 @@
  fuse_main;
  fuse_main_compat1;
  fuse_main_compat2;
+ fuse_main_parsed_real;
  fuse_main_real;
  fuse_mount;
  fuse_mount_compat1;
  fuse_new;
  fuse_new_compat1;
  fuse_new_compat2;
+ fuse_parser;
  fuse_process_cmd;
  fuse_read_cmd;
  fuse_reply_err;
diff --new-file -u -r /home/patg/origcvs/fuse/lib/helper.c ./lib/helper.c
--- /home/patg/origcvs/fuse/lib/helper.c 2005-08-03 05:11:05.000000000 -0400
+++ ./lib/helper.c 2005-08-13 17:28:33.000000000 -0400
@@ -15,53 +15,253 @@
 #include <string.h>
 #include <limits.h>
 #include <signal.h>
+#ifdef USE_UCLIBC
+#include <errno.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <libgen.h>
+#endif
+
 
 struct fuse *fuse_new_common(int fd, const char *opts,
                              const struct fuse_operations *op,
                              size_t op_size, int compat);
 
+static int opt_member(const char *opts, const char *opt);
+
+static int add_options(char **lib_optp, char **kernel_optp, const char *opts);
+
+
 static struct fuse *fuse_instance;
 
+#ifdef USE_UCLIBC
+struct argp_option {
+    const char *name;
+    int val;
+    char *arg;
+    int flags;
+    char *doc;
+};
+
+struct argp_state {
+    const char *name;
+    void *input;
+};
+
+#define ARGP_KEY_ARG 0
+#define ARGP_KEY_END            0x1000001
+#define ARGP_NO_ARGS 0x1000002
+#define ARGP_KEY_INIT           0x1000003
+#define ARGP_KEY_ERROR          0x1000005
+#define ARGP_ERR_UNKNOWN (-1)
+#define OPTION_DOC 0
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+
+static
+struct argp_option fuse_options[] = {
+    { 0,  0,  0, 0, "FUSE options:" },
+    { "debug",    'd', 0, 0, "enable debug output (implies -f)" },
+    { "fg",    'f', 0, 0, "foreground operation" },
+    { "single",    's', 0, 0, "disable multithreaded operation" },
+    { "ro",    'r', 0, 0, "mount read only (equivalent to '-o ro')" },
+    { "opt",    'o', "opt[,opt...]", 0, "mount options" },
+
+#ifndef USE_UCLIBC
+    /* For backward compatibility */
+    { 0,    'h', 0, OPTION_HIDDEN },
+
+#else
+    { "help",    'h', 0, 0, "display this help and exit" }
+};
+    
+struct argp_option mount_options[] = {
+#endif
+    { 0,  0,  0, 0, "Mount options:" },
+    { "default_permissions", 0, 0, OPTION_DOC , "enable permission checking"},
+    { "allow_other",  0, 0, OPTION_DOC, "allow access to other users" },
+    { "allow_root",   0, 0, OPTION_DOC, "allow access to root" },
+    { "kernel_cache", 0, 0, OPTION_DOC, "cache files in kernel" },
+    { "large_read",   0, 0, OPTION_DOC, "issue large read requests (2.4 only)"},
+    { "direct_io",    0, 0, OPTION_DOC, "use direct I/O" },
+    { "max_read=N",   0, 0, OPTION_DOC, "set maximum size of read requests" },
+    { "hard_remove",  0, 0, OPTION_DOC, "immediate removal (don't hide files)"},
+    { "debug",        0, 0, OPTION_DOC, "enable debug output" },
+    { "fsname=NAME",  0, 0, OPTION_DOC, "set filesystem name in mtab" },
+    { "use_ino",      0, 0, OPTION_DOC, "let filesystem set inode numbers" },
+    { "readdir_ino",  0, 0, OPTION_DOC, "try to fill in d_ino in readdir" },
+    { "nonempty",     0, 0, OPTION_DOC, "allow mounts over non-empty file/dir"},
+    { "umask=N",      0, 0, OPTION_DOC, "set file permissions (octal)" },
+    { "uid=N",        0, 0, OPTION_DOC, "set file owner" },
+    { "gid=N",        0, 0, OPTION_DOC, "set file group" },
+    { 0 }
+};
+
+#ifdef USE_UCLIBC
 static void usage(const char *progname)
 {
+    int i;
+    char argbuf[20];
+
     if (progname)
-        fprintf(stderr,
-                "usage: %s mountpoint [FUSE options]\n\n", progname);
+ fprintf(stderr,
+ "usage: %s [FUSE options] mountpoint\n\n", progname);
 
-    fprintf(stderr,
-            "FUSE options:\n"
-            "    -d                     enable debug output (implies -f)\n"
-            "    -f                     foreground operation\n"
-            "    -s                     disable multithreaded operation\n"
-            "    -r                     mount read only (equivalent to '-o ro')\n"
-            "    -o opt,[opt...]        mount options\n"
-            "    -h                     print help\n"
-            "\n"
-            "Mount options:\n"
-            "    default_permissions    enable permission checking\n"
-            "    allow_other            allow access to other users\n"
-            "    allow_root             allow access to root\n"
-            "    kernel_cache           cache files in kernel\n"
-            "    large_read             issue large read requests (2.4 only)\n"
-            "    direct_io              use direct I/O\n"
-            "    max_read=N             set maximum size of read requests\n"
-            "    hard_remove            immediate removal (don't hide files)\n"
-            "    debug                  enable debug output\n"
-            "    fsname=NAME            set filesystem name in mtab\n"
-            "    use_ino                let filesystem set inode numbers\n"
-            "    readdir_ino            try to fill in d_ino in readdir\n"
-            "    nonempty               allow mounts over non-empty file/dir\n"
-            "    umask=M                set file permissions (octal)\n"
-            "    uid=N                  set file owner\n"
-            "    gid=N                  set file group\n"
-            );
-}
+    puts ("FUSE options:");
+    for (i = 1; i < sizeof(fuse_options)/sizeof(struct argp_option); i++) {
+ if (fuse_options[i].arg) {
+    //memset (argbuf, 0, sizeof (argbuf));
+    snprintf(argbuf, 20, "%s=%s", fuse_options[i].name,
+          fuse_options[i].arg);
+    printf ("  -%c, --%-16s  %s\n", fuse_options[i].val,
+    argbuf,
+    fuse_options[i].doc);
+ } else
+    printf ("  -%c, --%-16s  %s\n", fuse_options[i].val,
+    fuse_options[i].name,
+    fuse_options[i].doc);
+    }
+
+    puts ("\nMount options:");
+    for (i = 1; i < (sizeof (mount_options)-sizeof(struct argp_option))/
+     sizeof (struct argp_option); i++)
+ printf ("  %-20s  %s\n", mount_options[i].name, mount_options[i].doc);
+}
+#endif
+
+struct setup_state {
+    char    *kernel_opts;
+    char    *lib_opts;
+    char    *mountpoint;
+    int     multithreaded;
+    int     background;
+};
+
+
+static int parse_opt (int key, char *arg, struct argp_state *state)
+{
+    int res;
+    struct setup_state * setup = *((struct setup_state**)state->input);
+
+    switch (key) {
+        case ARGP_KEY_INIT:
+            setup = malloc (sizeof (struct setup_state));
+            setup->kernel_opts  = NULL;
+            setup->lib_opts     = NULL;
+            setup->mountpoint   = NULL;
+            setup->multithreaded= 1;
+            setup->background   = 1;
+            *((struct setup_state**)state->input) = setup;
+            return 0;
+
+        case ARGP_KEY_END:
+            /* Need to assign the filesystem name a default */
+            if (!opt_member(setup->lib_opts, "fsname")) {
+                char *fsname_opt;
+                int namelen = strlen (state->name);
+
+                fsname_opt = alloca (namelen + 8);
+                memcpy (fsname_opt, "fsname=", 7);
+                memcpy (fsname_opt+7, state->name, namelen);
+                fsname_opt[namelen+7] = 0;
+
+                res = add_options(&setup->lib_opts, &setup->kernel_opts,
+                                  fsname_opt);
+                if (res < 0)
+                    return -EINVAL;
+            }
+
+            /* Fallback */
+        case ARGP_NO_ARGS:
+            if (!setup->mountpoint) {
+                fputs ("FUSE: missing mountpoint\n\n", stderr);
+#ifndef USE_UCLIBC
+                argp_usage (state);
+#else
+ fprintf(stderr, "see `%s -h' or `%s --help' for usage\n",
+ state->name, state->name);
+#endif
+ return -EINVAL;
+            }
 
-static void invalid_option(const char *argv[], int argctr)
+            return 0;
+
+        case ARGP_KEY_ERROR:
+            free(setup->kernel_opts);
+            free(setup->lib_opts);
+            free(setup->mountpoint);
+    free(setup);
+            return 0;
+
+        case ARGP_KEY_ARG:
+            if (setup->mountpoint)
+ fprintf (stderr, "FUSE: ignored argument %s\n", arg);
+
+            setup->mountpoint = strdup (arg);
+            if (setup->mountpoint == NULL) {
+                fputs ("FUSE: memory allocation failed\n", stderr);
+                return -ENOMEM;
+            }
+            return 0;
+
+        case 'o':
+            res = add_options(&setup->lib_opts, &setup->kernel_opts, arg);
+            if (res < 0)
+                return -EINVAL;
+            return 0;
+
+        case 'd':
+            res = add_options(&setup->lib_opts, &setup->kernel_opts, "debug");
+            if (res < 0)
+                return -EINVAL;
+            return 0;
+
+        case 'f':
+            setup->background = 0;
+            return 0;
+
+        case 'h':
+#ifndef USE_UCLIBC
+            argp_state_help (state, state->out_stream,
+     state->flags | ARGP_HELP_STD_HELP);
+    return 0;
+#else
+    usage (state->name);
+    return -1;
+#endif
+
+        case 'r':
+            res = add_options(&setup->lib_opts, &setup->kernel_opts, "ro");
+            if (res < 0)
+                return -EINVAL;
+            return 0;
+
+        case 's':
+            setup->multithreaded = 0;
+            return 0;
+    }
+
+    return ARGP_ERR_UNKNOWN;
+}
+
+#ifndef USE_UCLIBC
+static struct argp fuse_argp = {
+    .options    = fuse_options,
+    .parser     = &parse_opt,
+    .args_doc   = "mountpoint",
+    .doc        = "Mounts the filesystem at <mountpoint>"
+};
+
+static struct argp_child fuse_argp_child = { &fuse_argp, 0, "", 0 };
+
+struct argp_child  fuse_parser()
 {
-    fprintf(stderr, "fuse: invalid option: %s\n\n", argv[argctr]);
-    fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
+    return fuse_argp_child;
 }
+#endif
+
 
 static void exit_handler(int sig)
 {
@@ -177,134 +377,75 @@
     return 0;
 }
 
-static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts,
-                              char **lib_opts, char **mountpoint,
-                              int *multithreaded, int *background)
+static int fuse_parse_cmdline(struct setup_state ** setup,
+           int argc, char *argv[])
 {
-    int res;
-    int argctr;
-    const char *basename;
-    char *fsname_opt;
-
-    *kernel_opts = NULL;
-    *lib_opts = NULL;
-    *mountpoint = NULL;
-    *multithreaded = 1;
-    *background = 1;
-
-    basename = strrchr(argv[0], '/');
-    if (basename == NULL)
-        basename = argv[0];
-    else if (basename[1] != '\0')
-        basename++;
+#ifndef USE_UCLIBC
+    return argp_parse (&fuse_argp, argc, argv, 0, 0, setup);
 
-    fsname_opt = (char *) malloc(strlen(basename) + 64);
-    if (fsname_opt == NULL) {
-        fprintf(stderr, "fuse: memory allocation failed\n");
-        return -1;
-    }
-    sprintf(fsname_opt, "fsname=%s", basename);
-    res = add_options(lib_opts, kernel_opts, fsname_opt);
-    free(fsname_opt);
-    if (res == -1)
-        goto err;
+#else
+    static char shortopt[sizeof(fuse_options)/sizeof(struct argp_option)];
+    static struct option options[(sizeof(fuse_options)*sizeof(struct option))/
+  sizeof(struct argp_option)];
+
+    int i, c;
+    int res, shortidx=0, longidx=0;
+    struct argp_state state = { (const char*)basename(argv[0]), setup };
+
+    for (i=1; i < sizeof(fuse_options)/sizeof(struct argp_option); i++) {
+ if (isalnum(fuse_options[i].val))
+    shortopt[shortidx++] = fuse_options[i].val;
+
+ if (fuse_options[i].name) {
+    options[longidx].name = fuse_options[i].name;
+    options[longidx].has_arg = (int)fuse_options[i].arg;
+    options[longidx].val = fuse_options[i].val;
+    longidx++;
+ }
+    }
+
+    res = parse_opt (ARGP_KEY_INIT, optarg, &state);
+    if (res < 0)
+ return -1;
+
+    /* Parsing options */
+    for (;;) {
+ c = getopt_long (argc, argv, shortopt, options, NULL);
+ if (c < 0)
+    break;
+
+ res = parse_opt (c, optarg, &state);
+ if (res < 0)
+    goto err_parse;
+    }
+
+    /* Parsing arguments */
+    for (i=optind; i < argc; i++) {
+ res = parse_opt (ARGP_KEY_ARG, argv[i], &state);
+ if (res < 0)
+    goto err_parse;
+    }
+
+    /* The end */
+    res = parse_opt (ARGP_KEY_END, optarg, &state);
+    if (res < 0)
+ goto err_parse;
 
-    for (argctr = 1; argctr < argc; argctr ++) {
-        if (argv[argctr][0] == '-') {
-            if (strlen(argv[argctr]) == 2)
-                switch (argv[argctr][1]) {
-                case 'o':
-                    if (argctr + 1 == argc || argv[argctr+1][0] == '-') {
-                        fprintf(stderr, "missing option after -o\n");
-                        fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-                        goto err;
-                    }
-                    argctr ++;
-                    res = add_options(lib_opts, kernel_opts, argv[argctr]);
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'd':
-                    res = add_options(lib_opts, kernel_opts, "debug");
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'r':
-                    res = add_options(lib_opts, kernel_opts, "ro");
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'f':
-                    *background = 0;
-                    break;
-
-                case 's':
-                    *multithreaded = 0;
-                    break;
-
-                case 'h':
-                    usage(argv[0]);
-                    goto err;
-
-                default:
-                    invalid_option(argv, argctr);
-                    goto err;
-                }
-            else {
-                if (argv[argctr][1] == 'o') {
-                    res = add_options(lib_opts, kernel_opts, &argv[argctr][2]);
-                    if (res == -1)
-                        goto err;
-                } else if(strcmp(argv[argctr], "-ho") == 0) {
-                    usage(NULL);
-                    goto err;
-                } else {
-                    invalid_option(argv, argctr);
-                    goto err;
-                }
-            }
-        } else if (*mountpoint == NULL) {
-            *mountpoint = strdup(argv[argctr]);
-            if (*mountpoint == NULL) {
-                fprintf(stderr, "fuse: memory allocation failed\n");
-                goto err;
-            }
-        }
-        else {
-            invalid_option(argv, argctr);
-            goto err;
-        }
-    }
-
-    if (*mountpoint == NULL) {
-        fprintf(stderr, "missing mountpoint\n");
-        fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-        goto err;
-    }
     return 0;
-
- err:
-    free(*kernel_opts);
-    free(*lib_opts);
-    free(*mountpoint);
+    
+err_parse:
+    parse_opt (ARGP_KEY_ERROR, optarg, &state);
     return -1;
+#endif
 }
 
-static struct fuse *fuse_setup_common(int argc, char *argv[],
+static struct fuse *fuse_setup_common(struct setup_state * setup,
                                       const struct fuse_operations *op,
                                       size_t op_size,
-                                      char **mountpoint,
-                                      int *multithreaded,
                                       int *fd,
                                       int compat)
 {
     struct fuse *fuse;
-    int background;
-    char *kernel_opts;
-    char *lib_opts;
     int res;
 
     if (fuse_instance != NULL) {
@@ -312,21 +453,15 @@
         return NULL;
     }
 
-    res = fuse_parse_cmdline(argc, (const char **) argv, &kernel_opts,
-                             &lib_opts, mountpoint, multithreaded,
-                             &background);
-    if (res == -1)
-        return NULL;
-
-    *fd = fuse_mount(*mountpoint, kernel_opts);
+    *fd = fuse_mount(setup->mountpoint, setup->kernel_opts);
     if (*fd == -1)
         goto err_free;
 
-    fuse = fuse_new_common(*fd, lib_opts, op, op_size, compat);
+    fuse = fuse_new_common(*fd, setup->lib_opts, op, op_size, compat);
     if (fuse == NULL)
         goto err_unmount;
 
-    if (background && !opt_member(lib_opts, "debug")) {
+    if (setup->background && !opt_member(setup->lib_opts, "debug")) {
         res = daemon(0, 0);
         if (res == -1) {
             perror("fuse: failed to daemonize program\n");
@@ -339,38 +474,61 @@
         goto err_destroy;
 
     fuse_instance = fuse;
-    free(kernel_opts);
-    free(lib_opts);
+    free(setup->kernel_opts);
+    free(setup->lib_opts);
     return fuse;
 
  err_destroy:
     fuse_destroy(fuse);
  err_unmount:
-    fuse_unmount(*mountpoint);
+    fuse_unmount(setup->mountpoint);
  err_free:
-    free(kernel_opts);
-    free(lib_opts);
-    free(*mountpoint);
+    free(setup->kernel_opts);
+    free(setup->lib_opts);
+    free(setup->mountpoint);
+    free(setup);
     return NULL;
 }
 
+
+struct fuse *fuse_setup_parse (int argc, char *argv[],
+       const struct fuse_operations *op,
+       size_t op_size, char **mountpoint,
+       int *multithreaded, int *fd, int compat)
+{
+    struct fuse * fuse;
+    struct setup_state *setup;
+
+    if (fuse_parse_cmdline (&setup, argc, argv) < 0)
+ return NULL;
+
+    *mountpoint   = setup->mountpoint;
+    *multithreaded = setup->multithreaded;
+
+    fuse = fuse_setup_common (setup, op, op_size, fd, compat);
+    free (setup);
+
+    return fuse;
+}
+
 struct fuse *fuse_setup(int argc, char *argv[],
                           const struct fuse_operations *op,
                           size_t op_size, char **mountpoint,
                           int *multithreaded, int *fd)
 {
-    return fuse_setup_common(argc, argv, op, op_size, mountpoint,
+    return fuse_setup_parse (argc, argv, op, op_size, mountpoint,
                              multithreaded, fd, 0);
 }
 
+
 struct fuse *fuse_setup_compat2(int argc, char *argv[],
                                  const struct fuse_operations_compat2 *op,
                                  char **mountpoint, int *multithreaded,
                                  int *fd)
 {
-    return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
-                             sizeof(struct fuse_operations_compat2),
-                             mountpoint, multithreaded, fd, 21);
+    return fuse_setup_parse (argc, argv, (struct fuse_operations *) op,
+     sizeof(struct fuse_operations_compat2),
+     mountpoint, multithreaded, fd, 21);
 }
 
 void fuse_teardown(struct fuse *fuse, int fd, char *mountpoint)
@@ -386,37 +544,56 @@
     free(mountpoint);
 }
 
-static int fuse_main_common(int argc, char *argv[],
+
+static int fuse_main_common(struct setup_state * setup,
                             const struct fuse_operations *op, size_t op_size,
                             int compat)
 {
     struct fuse *fuse;
-    char *mountpoint;
-    int multithreaded;
     int res;
     int fd;
 
-    fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
-                             &multithreaded, &fd, compat);
+    fuse = fuse_setup_common(setup, op, op_size, &fd, compat);
     if (fuse == NULL)
         return 1;
 
-    if (multithreaded)
+    if (setup->multithreaded)
         res = fuse_loop_mt(fuse);
     else
         res = fuse_loop(fuse);
 
-    fuse_teardown(fuse, fd, mountpoint);
+    fuse_teardown (fuse, fd, setup->mountpoint);
+    free (setup);
     if (res == -1)
         return 1;
 
     return 0;
 }
 
+
+static int fuse_main_parse (int argc, char *argv[],
+                            const struct fuse_operations *op, size_t op_size,
+                            int compat)
+{
+    int res;
+    struct setup_state * setup;
+    res = fuse_parse_cmdline (&setup, argc, argv);
+    if (res < 0)
+ return res;
+
+    return fuse_main_common (setup, op, op_size, compat);
+}
+
 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
                    size_t op_size)
 {
-    return fuse_main_common(argc, argv, op, op_size, 0);
+    return fuse_main_parse (argc, argv, op, op_size, 0);
+}
+
+int fuse_main_parsed_real (void * input, const struct fuse_operations *op,
+   size_t op_size)
+{
+    return fuse_main_common (input, op, op_size, 0);
 }
 
 #undef fuse_main
@@ -429,14 +606,14 @@
 void fuse_main_compat1(int argc, char *argv[],
                       const struct fuse_operations_compat1 *op)
 {
-    fuse_main_common(argc, argv, (struct fuse_operations *) op,
+    fuse_main_parse (argc, argv, (struct fuse_operations *) op,
                      sizeof(struct fuse_operations_compat1), 11);
 }
 
 int fuse_main_compat2(int argc, char *argv[],
                       const struct fuse_operations_compat2 *op)
 {
-    return fuse_main_common(argc, argv, (struct fuse_operations *) op,
+    return fuse_main_parse (argc, argv, (struct fuse_operations *) op,
                             sizeof(struct fuse_operations_compat2), 21);
 }
 
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Miklos Szeredi
> Still, getopt_long is a GNU extension of SUSv3, which can be removed
> from uClibc at compile time. Although it is enabled by default in the
> official uClibc distribution, those who disable it woundn't be able to
> compile FUSE.
>
> This could be fixed by using the SUSv3 version of getopt. This shouldn't
> be a problem, unless users of the library begin to use long options.
> It just depends on the desired level of portability. Tell me if you want
> to fallback to SUSv3 getopt.

My feeling is, that if possible this should be detected at ./configure
time and the best available method used.

> Also, the major current problem is that the argp interface is completely
> disabled when using uClibc, meaning its users would have to be sure
> nobody would use their filesystem with uClibc.

By disabled, you mean it's missing from uClibc, or that it's disabled
by default?

> It could be possible to reimplement the argp behavior in the helper,
> although this would at least double the size of the module. The two
> other options I can think of are ignoring the issue and not including
> the argp parser.
> Could you give me your opinion on this.

I think it's OK if it takes a bit more effort to compile FUSE and
filesystems for a uClibc system (e.g. having to install a separate
argp library), but it should work, and should not be too much
crippled.

Miklos


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Miklos Szeredi
In reply to this post by Patrick Guimond
> I think I could fix both, tell me if you interested in the feature.

There is one thing though, why argp might not be the best interface
for FUSE: it's too generic.  Filesystems should only need to parse the
'-o opt[,...]' syntax and filter out their own options (and the mount
source, if there's one).

Does argp support this kind of option manipulation at all?

So maybe a specialized option parsing interface for FUSE might not be
such a bad idea.  It would mean less trouble and less code for systems
not having native argp implementation, and would probably be easier to
use by the filesystems.

Hmm?

Miklos


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Patrick Guimond
In reply to this post by Miklos Szeredi
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Miklos Szeredi wrote:

>>Still, getopt_long is a GNU extension of SUSv3, which can be removed
>>from uClibc at compile time. Although it is enabled by default in the
>>official uClibc distribution, those who disable it woundn't be able to
>>compile FUSE.
>>
>>This could be fixed by using the SUSv3 version of getopt. This shouldn't
>>be a problem, unless users of the library begin to use long options.
>>It just depends on the desired level of portability. Tell me if you want
>>to fallback to SUSv3 getopt.
>
>
> My feeling is, that if possible this should be detected at ./configure
> time and the best available method used.
>
>
>>Also, the major current problem is that the argp interface is completely
>>disabled when using uClibc, meaning its users would have to be sure
>>nobody would use their filesystem with uClibc.
>
>
> By disabled, you mean it's missing from uClibc, or that it's disabled
> by default?
>

argp is completely missing from uClibc. The only way to get `parsing
help' is by using getopt (and as mentioned, GNU getopt_long and getopt
if not disabled)

>
>>It could be possible to reimplement the argp behavior in the helper,
>>although this would at least double the size of the module. The two
>>other options I can think of are ignoring the issue and not including
>>the argp parser.
>>Could you give me your opinion on this.
>
>
> I think it's OK if it takes a bit more effort to compile FUSE and
> filesystems for a uClibc system (e.g. having to install a separate
> argp library), but it should work, and should not be too much
> crippled.
>
> Miklos
>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2-ecc0.1.6 (GNU/Linux)

iD8DBQFC/03/0X14v95lmw4RAqp/AJ0S6SBDbnQjPPUQfuREYP6FUZHdJwCfRDFT
UzWtzBU22MkxN9M9BTiyrOA=
=NfEa
-----END PGP SIGNATURE-----


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Patrick Guimond
In reply to this post by Miklos Szeredi
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Miklos Szeredi wrote:
>>I think I could fix both, tell me if you interested in the feature.
>
>
> There is one thing though, why argp might not be the best interface
> for FUSE: it's too generic.  Filesystems should only need to parse the
> '-o opt[,...]' syntax and filter out their own options (and the mount
> source, if there's one).
>
> Does argp support this kind of option manipulation at all?

If all options are to be passed by the -o switch, I think it's best to
not use argp then, since it's purpose is to parse switches.

>
> So maybe a specialized option parsing interface for FUSE might not be
> such a bad idea.  It would mean less trouble and less code for systems
> not having native argp implementation, and would probably be easier to
> use by the filesystems.
>

Then this may be the best option. I'll take a look at this and try to
come up with something.


Thanks,
patg


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2-ecc0.1.6 (GNU/Linux)

iD8DBQFC/04J0X14v95lmw4RAqLVAKDEajGCFkvwagvOMeBVeuY1JF0uiwCfYwCg
ODoBy2BzAYRKNU9xTqrGoU0=
=r84U
-----END PGP SIGNATURE-----


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Miklos Szeredi
> If all options are to be passed by the -o switch, I think it's best to
> not use argp then, since it's purpose is to parse switches.

OK.  I think it's best if every option can be specified with -o.  This
way filesystems can be mounted from /etc/fstab for example.  There
could be a shorthand for some options, like '-p PORT' is a shorthand
for '-o port=PORT' in sshfs.  And of course help options like '--help'
and '--version' don't need a corresponding '-o' option.

> Then this may be the best option. I'll take a look at this and try to
> come up with something.

Have a look at opts.c in sshfs.  Something like that would be all
right by me.  I'm sure you can improve upon it by your knowledge of
argp and getopt.

Miklos


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Lou Kamenov
On 14/08/05, Miklos Szeredi <[hidden email]> wrote:
[..]

I used to have a mount.fuse in awk which would parse fs options.
for example:
mount -t fuse -o fs=ftpfs,etc,etc whatever arguments.

for ssh i'd have done something like:
mount -t fuse -o fs=sshfs,port=22,ip=key everything but fs= would be
translated to --port 22 --ip key whatever, its just a thought.

you ought to take configure out of fuse... what its role exactly?

l


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Miklos Szeredi
> I used to have a mount.fuse in awk which would parse fs options.
> for example:
> mount -t fuse -o fs=ftpfs,etc,etc whatever arguments.
>
> for ssh i'd have done something like:
> mount -t fuse -o fs=sshfs,port=22,ip=key everything but fs= would be
> translated to --port 22 --ip key whatever, its just a thought.

Why not just leave it as it is?  I think specifying mount options with
'-o opt' is fine.

In effect every FUSE filesystem is just a specialized "mount" command.
The advantage of not always going through mount are:

  - It's possible to have more flexible unprivileged mount policy
    (iow, normal user can mount _any_ FUSE filesystem)

  - It's possible to do foreground debugging of the filesystem daemon.

  - It's possible to have shorthand forms for the common mount options

> you ought to take configure out of fuse...

I'm not sure what you mean by this.  Can you elaborate?

Thanks,
Miklos


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
fuse-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: command line options

Patrick Guimond
In reply to this post by Miklos Szeredi
Miklos Szeredi wrote:

>>If all options are to be passed by the -o switch, I think it's best to
>>not use argp then, since it's purpose is to parse switches.
>
>
> OK.  I think it's best if every option can be specified with -o.  This
> way filesystems can be mounted from /etc/fstab for example.  There
> could be a shorthand for some options, like '-p PORT' is a shorthand
> for '-o port=PORT' in sshfs.  And of course help options like '--help'
> and '--version' don't need a corresponding '-o' option.
>
The attached patch implements this kind of behavior, giving the user a
getopt(3p) like interface via fuse_getopt.

The fuse_getopt behavior implements the -o opt[=value], returning an
index to the passed long option the same way that does GNU's getopt_long

The current implementation should be backward compatible when using the
fuse_main interface, as it parses the options before and after the
mountpoint, which would enable users to use

  mount_command [options]... mountpoint [options]...

But it does NOT work (and thus the behavior is not `backward' compatible
in this case) when the client uses the fuse_getopt interface, as it uses
the POSIX getopt(3). So, when getting the options, fuse_getopt will
return -1 at the first encountered argument, only allowing to specify
options _before_ the arguments, as in

  mount_command [options]... arguments...

This is done to get all arguments linearly in the remaining of argv

This could be resolved by using GNU getopt(3), which parses options
mixed with arguments, but is NOT POSIX compliant as it permutes elements
of the argv vector. (POSIX getopt should not change the argv elements
order).

Now, the question is, would it be better to use GNU getopt(3) for
parsing arguments or is it necessary to use the POSIX interface?

As said in a previous mail, the GNU getopt interface is enabled by
default in the current uClibc release, but it can be disabled. If the
decision is to use a GNU getopt (and first if the fuse_getopt is used at
all), it should be possible to recreate the GNU behavior when parsing
with a SUSv3 getopt by permuting the argv elements ourselves, adding a
small layer of compatibility.

All comments are welcome

Thanks,
patg

diff -u -r --new-file ../../orig/fuse/example/hello_opt.c ./example/hello_opt.c
--- ../../orig/fuse/example/hello_opt.c 1969-12-31 19:00:00.000000000 -0500
+++ ./example/hello_opt.c 2005-08-22 09:05:53.000000000 -0400
@@ -0,0 +1,171 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001-2005  Miklos Szeredi <[hidden email]>
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include <fuse.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+static const char *hello_str = "Hello World!\n";
+static const char *hello_path = "/hello";
+
+static int hello_getattr(const char *path, struct stat *stbuf)
+{
+    int res = 0;
+
+    memset(stbuf, 0, sizeof(struct stat));
+    if(strcmp(path, "/") == 0) {
+        stbuf->st_mode = S_IFDIR | 0755;
+        stbuf->st_nlink = 2;
+    }
+    else if(strcmp(path, hello_path) == 0) {
+        stbuf->st_mode = S_IFREG | 0444;
+        stbuf->st_nlink = 1;
+        stbuf->st_size = strlen(hello_str);
+    }
+    else
+        res = -ENOENT;
+
+    return res;
+}
+
+static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                         off_t offset, struct fuse_file_info *fi)
+{
+    (void) offset;
+    (void) fi;
+
+    if(strcmp(path, "/") != 0)
+        return -ENOENT;
+
+    filler(buf, ".", NULL, 0);
+    filler(buf, "..", NULL, 0);
+    filler(buf, hello_path + 1, NULL, 0);
+
+    return 0;
+}
+
+static int hello_open(const char *path, struct fuse_file_info *fi)
+{
+    if(strcmp(path, hello_path) != 0)
+        return -ENOENT;
+
+    if((fi->flags & 3) != O_RDONLY)
+        return -EACCES;
+
+    return 0;
+}
+
+static int hello_read(const char *path, char *buf, size_t size, off_t offset,
+                      struct fuse_file_info *fi)
+{
+    size_t len;
+    (void) fi;
+    if(strcmp(path, hello_path) != 0)
+        return -ENOENT;
+
+    len = strlen(hello_str);
+    if (offset < len) {
+        if (offset + size > len)
+            size = len - offset;
+        memcpy(buf, hello_str + offset, size);
+    } else
+        size = 0;
+
+    return size;
+}
+
+static struct fuse_operations hello_oper = {
+    .getattr = hello_getattr,
+    .readdir = hello_readdir,
+    .open = hello_open,
+    .read = hello_read,
+};
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static struct fuse_opt opts[] = {
+    { "custom", 1, 'c' },
+    { "witharg", 1, 0 },
+    { "other" },
+    { 0 }
+};
+
+void usage (const char * progname)
+{
+    fprintf (stderr, "Usage: %s [OPTION]... mountpoint\n\n", progname);
+    fputs ("Custom options:\n"
+   "    -g option      option with argument example\n"
+   "    -c             option without argument example\n\n", stderr);
+
+    fuse_main_parsed (NULL, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+    int c;
+    int optidx;
+
+    for (;;) {
+ c = fuse_getopt (argc, argv, ":c:g", opts, &optidx);
+
+ if (c == -2) {
+    puts ("internal FUSE error received");
+    return 1;
+ }
+
+ if (c == -1)
+    break;
+
+ switch (c) {
+    case 0:
+ if (opts[optidx].has_arg)
+    printf ("option -o %s has been passed with argument, %s\n",
+    opts[optidx].name, optarg);
+ else
+    printf ("option -o %s has been passed\n",
+    opts[optidx].name);
+ break;
+    case 'c':
+ printf ("option -%c passed with argument %s\n", c, optarg);
+ break;
+    case 'g':
+ puts ("option -g passed");
+ break;
+    case 'h':
+ usage (argv[0]);
+ return 0;
+    case ':':
+ if (optopt == 'o')
+    fprintf (stderr, "option -o %s missing argument\n",
+     opts[optidx].name);
+ else
+    fprintf (stderr, "option -%c missing argument\n",
+     optopt);
+ break;
+    case '?':
+ if (optopt != 'o')
+    fprintf (stderr, "unknown option: -%c\n", optopt);
+ break;
+ }
+    }
+
+    if (optind >= argc) {
+        fputs ("Missing mountpoint\n", stderr);
+ return 1;
+    }
+
+    /* `optind' points to the first argument */
+    fuse_main_parsed (argv[optind], &hello_oper);
+
+    return 0;
+}
+
diff -u -r --new-file ../../orig/fuse/example/Makefile.am ./example/Makefile.am
--- ../../orig/fuse/example/Makefile.am 2005-07-13 10:07:55.000000000 -0400
+++ ./example/Makefile.am 2005-08-22 09:06:08.000000000 -0400
@@ -1,10 +1,11 @@
 ## Process this file with automake to produce Makefile.in
 
-noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll
+noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll hello_opt
 
 fusexmp_SOURCES = fusexmp.c
 fusexmp_fh_SOURCES = fusexmp_fh.c
 null_SOURCES = null.c
 hello_SOURCES = hello.c
+hello_opt_SOURCES = hello_opt.c
 
 LDADD = ../lib/libfuse.la -lpthread
diff -u -r --new-file ../../orig/fuse/include/fuse.h ./include/fuse.h
--- ../../orig/fuse/include/fuse.h 2005-08-15 09:19:07.000000000 -0400
+++ ./include/fuse.h 2005-08-22 09:11:31.000000000 -0400
@@ -335,6 +335,33 @@
     void *private_data;
 };
 
+/*
+ * Option parsing element
+ * */
+struct fuse_opt {
+    const char  *name;      /* Name used in the -o option */
+    int         has_arg;      
+    int         val;        /* Value returned by the fuse_getopt call
+                               unless an error occurs (same behavior as
+                               in getopt_long(3) ) */
+};
+
+
+
+/*
+ * Option parsing function
+ *
+ * @param argc the argument counter passed to the main() function
+ * @param argv the argument vector passed to the main() function
+ * @param optstring single character options as used in getopt(3)
+ * @param opts extended fuse options used in -o switches
+ * @param option_index index of the extended option when using -o switches
+ * @return status as in getopt(3), with extended fuse options returning 'o'
+ */
+int fuse_getopt (int argc, char *argv[], const char *optstring,
+         const struct fuse_opt * opts, int * option_index);
+
+
 /*
  * Main function of FUSE.
  *
@@ -363,6 +390,20 @@
 #define fuse_main(argc, argv, op) \
             fuse_main_real(argc, argv, op, sizeof(*(op)))
 
+
+/*
+ * Main function for FUSE when command line has already been parsed
+ *
+ * @param mountpoint path to the mountpoint
+ * @param op the file system operation
+ * @return 0 on success, nonzero on failure
+ */
+/*
+int fuse_main_parsed(const char *mountpoint, const struct fuse_operations *op);
+*/
+#define fuse_main_parsed(mountpoint, op) \
+            fuse_main_parsed_real(mountpoint, op, sizeof(*(op)))
+
 /* ----------------------------------------------------------- *
  * More detailed API                                           *
  * ----------------------------------------------------------- */
@@ -474,6 +515,8 @@
  */
 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
                    size_t op_size);
+int fuse_main_parsed_real(const char *mountpoint,
+  const struct fuse_operations *op, size_t op_size);
 
 /* ----------------------------------------------------------- *
  * Advanced API for event handling, don't worry about this...  *
diff -u -r --new-file ../../orig/fuse/lib/fuse_versionscript ./lib/fuse_versionscript
--- ../../orig/fuse/lib/fuse_versionscript 2005-08-15 10:39:35.000000000 -0400
+++ ./lib/fuse_versionscript 2005-08-22 08:51:26.000000000 -0400
@@ -4,6 +4,7 @@
  fuse_exit;
  fuse_exited;
  fuse_get_context;
+ fuse_getopt;
  fuse_invalidate;
  fuse_is_lib_option;
  fuse_loop;
@@ -13,6 +14,7 @@
  fuse_main_compat1;
  fuse_main_compat2;
  fuse_main_real;
+ fuse_main_parsed_real;
  fuse_mount;
  fuse_mount_compat1;
  fuse_new;
diff -u -r --new-file ../../orig/fuse/lib/helper.c ./lib/helper.c
--- ../../orig/fuse/lib/helper.c 2005-08-15 09:19:07.000000000 -0400
+++ ./lib/helper.c 2005-08-22 09:13:26.000000000 -0400
@@ -12,6 +12,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <libgen.h>
 #include <string.h>
 #include <limits.h>
 #include <signal.h>
@@ -53,11 +54,16 @@
             );
 }
 
-static void invalid_option(const char *argv[], int argctr)
-{
-    fprintf(stderr, "fuse: invalid option: %s\n\n", argv[argctr]);
-    fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-}
+static struct {
+    int    status;
+    char    *kernel_opts;
+    char    *lib_opts;
+    char    *mountpoint;
+    int     multithreaded;
+    int     background;
+} setup;
+
+
 
 static void exit_handler(int sig)
 {
@@ -100,6 +106,8 @@
     return 0;
 }
 
+
+
 static int opt_member(const char *opts, const char *opt)
 {
     const char *e, *s = opts;
@@ -132,7 +140,7 @@
     return 0;
 }
 
-static int add_options(char **lib_optp, char **kernel_optp, const char *opts)
+static int add_options(const char *opts)
 {
     char *xopts = strdup(opts);
     char *s = xopts;
@@ -148,15 +156,15 @@
     while((opt = strsep(&s, ",")) != NULL) {
         int res;
         if (fuse_is_lib_option(opt)) {
-            res = add_option_to(opt, lib_optp);
+            res = add_option_to(opt, &setup.lib_opts);
             /* Compatibility hack */
             if (strcmp(opt, "allow_root") == 0 && res != -1) {
                 has_allow_root = 1;
-                res = add_option_to("allow_other", kernel_optp);
+                res = add_option_to("allow_other", &setup.kernel_opts);
             }
         }
         else {
-            res = add_option_to(opt, kernel_optp);
+            res = add_option_to(opt, &setup.kernel_opts);
             if (strcmp(opt, "allow_other") == 0)
                 has_allow_other = 1;
         }
@@ -173,134 +181,337 @@
     return 0;
 }
 
-static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts,
-                              char **lib_opts, char **mountpoint,
-                              int *multithreaded, int *background)
+static struct fuse_opt internal_opts[] = {
+    { "default_permissions" },
+    { "allow_other" },
+    { "allow_root" },
+    { "kernel_cache" },
+    { "large_read" },
+    { "direct_io" },
+    { "max_read=N", 1 },
+    { "hard_remove" },
+    { "debug" },
+    { "fsname=NAME", 1 },
+    { "use_ino" },
+    { "readdir_ino" },
+    { "nonempty" },
+    { "umask=M", 1 },
+    { "uid=N", 1 },
+    { "gid=N", 1 },
+    { 0 }
+};
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static char * start_optarg;
+static char * next_subopt;
+
+static int get_subopt (char ** name)
+{
+    if (start_optarg == optarg) {
+ /* First run */
+ next_subopt = optarg;
+    } else {
+ if (optarg)
+    optarg[-1] = '=';
+ optarg = start_optarg;
+
+ if (!next_subopt) {
+    start_optarg = NULL;
+    return 0;
+ }
+ next_subopt[-1] = ',';
+    }
+
+    while (*next_subopt == ',')
+ next_subopt++;
+
+    if (!*next_subopt) {
+ start_optarg = NULL;
+ return 0;
+    }
+
+    *name = next_subopt;
+    next_subopt = strchr (next_subopt, ',');
+    if (next_subopt) {
+ *next_subopt = 0;
+ next_subopt++;
+    } else if (!**name) {
+ start_optarg = NULL;
+ return 0;
+    }
+
+    start_optarg = optarg;
+    optarg = strchr (*name, '=');
+    if (optarg) {
+ *optarg = 0;
+ optarg++;
+ if (!*optarg || *optarg == ',') {
+    next_subopt = optarg;
+    optarg = NULL;
+ }
+    }
+
+    return 'o';
+}
+
+
+static int verify_option (const char * name, const struct fuse_opt * opts,
+              int * optidx, int verbose_unknown, int verbose_noarg)
+{
+    const struct fuse_opt *opt;
+
+    for (opt = opts; opt->name; opt++) {
+ if (strcmp (opt->name, name))
+    continue;
+    
+ *optidx = opt - opts;
+ if (opt->has_arg && !optarg) {
+    if (verbose_noarg && opterr)
+ fprintf (stderr, "missing argument to option -o %s\n", name);
+    optopt = 'o';
+    return ':';
+ }
+
+ return 'o';
+    }
+
+    if (verbose_unknown && opterr)
+ fprintf (stderr, "unknown option -o %s\n", name);
+
+    optopt = 'o';
+    return '?';
+}
+
+
+static int nextopt (int argc, char *argv[], char ** subopt)
+{
+    int c, res;
+    int optidx;
+    int save_opterr;
+
+    for (;;) {
+ while (start_optarg) {
+    res = get_subopt (subopt);
+
+    if (!res)
+ break;
+
+    c = verify_option (*subopt, internal_opts, &optidx, 0, 1);
+    if (c == '?')
+ return 'o';
+
+    if (c == ':')
+ continue;
+
+    if (optarg) {
+ int optlen = optarg - *subopt - 1;
+ int arglen = strlen (optarg);
+ char opt[optlen + arglen + 1];
+
+ memcpy (opt, *subopt, optlen);
+ opt[optlen] = '=';
+ memcpy (opt + optlen + 1, optarg, optlen);
+ opt[optlen + arglen + 1] = 0;
+ res = add_options (opt);
+    } else
+ res = add_options(*subopt);
+
+    if (res)
+ return -2;
+ }
+
+ save_opterr = opterr;
+ opterr = 0;
+ c = getopt (argc, argv, "+:h:dfsro:-:");
+ opterr = save_opterr;
+
+ if (c < 0)
+    return -1;
+
+ switch (c) {
+            case 'o':
+ start_optarg = optarg;
+ break;
+
+            case 'd':
+                res = add_options("debug");
+                if (res == -1)
+                    return -2;
+                break;
+
+            case 'r':
+                res = add_options("ro");
+                if (res == -1)
+                    return -2;
+                break;
+            case 'f':
+                setup.background = 0;
+                break;
+
+            case 's':
+                setup.multithreaded = 0;
+                break;
+
+            case '-':
+                /* The only known long option is `help' */
+                if (strcmp (optarg, "help"))
+                   break;
+                optopt = 'h';
+
+            case ':':
+                if (optopt == 'h')
+    return 'h';
+
+ if (opterr) {
+    fprintf(stderr, "missing option after -%c\n", optopt);
+    fprintf(stderr, "see `%s -h' for usage\n",
+    basename(argv[0]));
+ }
+ break;
+
+    case 'h':
+ if (optarg[0] == 'o' && !optarg[1]) {
+    if (opterr)
+ usage(NULL);
+    return 'h';
+ }
+
+ if (opterr)
+    usage (basename(argv[0]));
+ return 'h';
+
+    case '?':
+ /* Not our option, maybe a custom one */
+ return '?';
+ }
+    }
+}
+
+
+int fuse_getopt (int argc, char *argv[], const char * optstring,
+ const struct fuse_opt * opts, int * optidx)
+{
+    int c, verbose = 0;
+    char * subopt;
+
+    if (setup.status < 0)
+ return -2;
+
+    if (!setup.status) {
+ int namelen;
+ const char *fsname = basename (argv[0]);
+ namelen = strlen (fsname);
+
+ char fsnameopt[namelen + 8];
+ memcpy (fsnameopt, "fsname=", 7);
+ memcpy (fsnameopt+7, fsname, namelen);
+ fsnameopt[namelen+7] = 0;
+ if (add_options (fsnameopt)) {
+    setup.status = -1;
+    return -2;
+ }
+
+ setup.multithreaded = 1;
+ setup.background    = 1;
+ setup.status    = 1;
+    }
+
+    c = nextopt (argc, argv, &subopt);
+
+    if (c == -2) {
+ free (setup.kernel_opts);
+ free (setup.lib_opts);
+
+ setup.status = -1;
+ return c;
+    }
+
+    if (c == '?') {
+ optind--;
+ return getopt (argc, argv, optstring);
+    }
+
+    if (c == 'o') {
+ if (optstring[0] != ':' && ((optstring[0] =='+' || optstring[0] == '-')
+                                     && optstring[1] != ':'))
+    verbose = 1;
+ c = verify_option (subopt, opts, optidx, verbose, verbose);
+ if (c == 'o')
+    return opts[*optidx].val;
+ if (c == ':' && opts[*optidx].val)
+    optopt = opts[*optidx].val;
+    }
+
+    return c;
+}
+
+static int parse_cmdline(int argc, char *argv[])
 {
     int res;
-    int argctr;
-    const char *basename;
-    char *fsname_opt;
-
-    *kernel_opts = NULL;
-    *lib_opts = NULL;
-    *mountpoint = NULL;
-    *multithreaded = 1;
-    *background = 1;
-
-    basename = strrchr(argv[0], '/');
-    if (basename == NULL)
-        basename = argv[0];
-    else if (basename[1] != '\0')
-        basename++;
+    int indsave;
+    char *name;
 
-    fsname_opt = (char *) malloc(strlen(basename) + 64);
-    if (fsname_opt == NULL) {
-        fprintf(stderr, "fuse: memory allocation failed\n");
-        return -1;
+    res = nextopt (argc, argv, &name);
+    if (res == -2)
+ goto err_free;
+
+    if (res == 'h') {
+ usage (basename(argv[0]));
+        goto err_free;
     }
-    sprintf(fsname_opt, "fsname=%s", basename);
-    res = add_options(lib_opts, kernel_opts, fsname_opt);
-    free(fsname_opt);
-    if (res == -1)
-        goto err;
 
-    for (argctr = 1; argctr < argc; argctr ++) {
-        if (argv[argctr][0] == '-') {
-            if (strlen(argv[argctr]) == 2)
-                switch (argv[argctr][1]) {
-                case 'o':
-                    if (argctr + 1 == argc || argv[argctr+1][0] == '-') {
-                        fprintf(stderr, "missing option after -o\n");
-                        fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-                        goto err;
-                    }
-                    argctr ++;
-                    res = add_options(lib_opts, kernel_opts, argv[argctr]);
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'd':
-                    res = add_options(lib_opts, kernel_opts, "debug");
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'r':
-                    res = add_options(lib_opts, kernel_opts, "ro");
-                    if (res == -1)
-                        goto err;
-                    break;
-
-                case 'f':
-                    *background = 0;
-                    break;
-
-                case 's':
-                    *multithreaded = 0;
-                    break;
-
-                case 'h':
-                    usage(argv[0]);
-                    goto err;
-
-                default:
-                    invalid_option(argv, argctr);
-                    goto err;
-                }
-            else {
-                if (argv[argctr][1] == 'o') {
-                    res = add_options(lib_opts, kernel_opts, &argv[argctr][2]);
-                    if (res == -1)
-                        goto err;
-                } else if(strcmp(argv[argctr], "-ho") == 0) {
-                    usage(NULL);
-                    goto err;
-                } else {
-                    invalid_option(argv, argctr);
-                    goto err;
-                }
-            }
-        } else if (*mountpoint == NULL) {
-            *mountpoint = strdup(argv[argctr]);
-            if (*mountpoint == NULL) {
-                fprintf(stderr, "fuse: memory allocation failed\n");
-                goto err;
-            }
-        }
-        else {
-            invalid_option(argv, argctr);
-            goto err;
-        }
+    if (res != -1)
+ goto err_unknown;
+
+    if (optind >= argc) {
+ fputs   ("FUSE: missing mountpoint\n", stderr);
+ fprintf (stderr, "FUSE: see `%s -h' for usage\n",
+ basename(argv[0]));
+ goto err_free;
+    }
+
+    setup.mountpoint = strdup (argv[optind]);
+
+    indsave = optind;
+    optind = 1;
+    res = nextopt (argc-indsave, argv+indsave, &name);
+    if (res == -2)
+ goto err_free;
+
+    if (res == 'h') {
+ usage (basename(argv[0]));
+        goto err_free;
     }
 
-    if (*mountpoint == NULL) {
-        fprintf(stderr, "missing mountpoint\n");
-        fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
-        goto err;
+    if (res != -1)
+ goto err_unknown;
+
+    optind += indsave;
+    if (argc - optind > 1) {
+ fputs ("FUSE: only one mountpoint is allowed\n", stderr);
+ goto err_free;
     }
+
     return 0;
 
- err:
-    free(*kernel_opts);
-    free(*lib_opts);
-    free(*mountpoint);
+err_unknown:
+    fprintf (stderr, "unknown option -%c\n", optopt);
+    fprintf (stderr, "see `%s -h' for usage\n", basename(argv[0]));
+
+err_free:
+    free (setup.kernel_opts);
+    free (setup.lib_opts);
+    free (setup.mountpoint);
     return -1;
 }
 
-static struct fuse *fuse_setup_common(int argc, char *argv[],
-                                      const struct fuse_operations *op,
-                                      size_t op_size,
-                                      char **mountpoint,
-                                      int *multithreaded,
-                                      int *fd,
-                                      int compat)
+
+static struct fuse *fuse_setup_common(const struct fuse_operations *op,
+                                      size_t op_size, int *fd, int compat)
 {
     struct fuse *fuse;
-    int background;
-    char *kernel_opts;
-    char *lib_opts;
     int res;
 
     if (fuse_instance != NULL) {
@@ -308,21 +519,15 @@
         return NULL;
     }
 
-    res = fuse_parse_cmdline(argc, (const char **) argv, &kernel_opts,
-                             &lib_opts, mountpoint, multithreaded,
-                             &background);
-    if (res == -1)
-        return NULL;
-
-    *fd = fuse_mount(*mountpoint, kernel_opts);
+    *fd = fuse_mount(setup.mountpoint, setup.kernel_opts);
     if (*fd == -1)
         goto err_free;
 
-    fuse = fuse_new_common(*fd, lib_opts, op, op_size, compat);
+    fuse = fuse_new_common(*fd, setup.lib_opts, op, op_size, compat);
     if (fuse == NULL)
         goto err_unmount;
 
-    if (background && !opt_member(lib_opts, "debug")) {
+    if (setup.background && !opt_member(setup.lib_opts, "debug")) {
         res = daemon(0, 0);
         if (res == -1) {
             perror("fuse: failed to daemonize program\n");
@@ -335,36 +540,49 @@
         goto err_destroy;
 
     fuse_instance = fuse;
-    free(kernel_opts);
-    free(lib_opts);
+    free(setup.kernel_opts);
+    free(setup.lib_opts);
     return fuse;
 
  err_destroy:
     fuse_destroy(fuse);
  err_unmount:
-    fuse_unmount(*mountpoint);
+    fuse_unmount(setup.mountpoint);
  err_free:
-    free(kernel_opts);
-    free(lib_opts);
-    free(*mountpoint);
+    free(setup.kernel_opts);
+    free(setup.lib_opts);
+    free(setup.mountpoint);
     return NULL;
 }
 
-struct fuse *fuse_setup(int argc, char *argv[],
-                          const struct fuse_operations *op,
-                          size_t op_size, char **mountpoint,
-                          int *multithreaded, int *fd)
+static struct fuse *fuse_setup_parse (int argc, char *argv[],
+      const struct fuse_operations *op,
+      size_t op_size, char **mountpoint,
+      int *multithreaded, int *fd, int compat)
 {
-    return fuse_setup_common(argc, argv, op, op_size, mountpoint,
-                             multithreaded, fd, 0);
+    if (parse_cmdline (argc, argv))
+ return NULL;
+
+    return fuse_setup_common(op, op_size, fd, compat);
+}
+
+struct fuse *fuse_setup (int argc, char *argv[],
+ const struct fuse_operations *op,
+ size_t op_size, char **mountpoint,
+ int *multithreaded, int *fd)
+
+{
+    return fuse_setup_parse(argc, argv, op, op_size, mountpoint,
+    multithreaded, fd, 0);
 }
 
+
 struct fuse *fuse_setup_compat2(int argc, char *argv[],
                                  const struct fuse_operations_compat2 *op,
                                  char **mountpoint, int *multithreaded,
                                  int *fd)
 {
-    return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
+    return fuse_setup_parse (argc, argv, (struct fuse_operations *) op,
                              sizeof(struct fuse_operations_compat2),
                              mountpoint, multithreaded, fd, 21);
 }
@@ -382,37 +600,57 @@
     free(mountpoint);
 }
 
-static int fuse_main_common(int argc, char *argv[],
-                            const struct fuse_operations *op, size_t op_size,
+static int fuse_main_common(const struct fuse_operations *op, size_t op_size,
                             int compat)
 {
     struct fuse *fuse;
-    char *mountpoint;
-    int multithreaded;
     int res;
     int fd;
 
-    fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
-                             &multithreaded, &fd, compat);
+    fuse = fuse_setup_common(op, op_size, &fd, compat);
     if (fuse == NULL)
         return 1;
 
-    if (multithreaded)
+    if (setup.multithreaded)
         res = fuse_loop_mt(fuse);
     else
         res = fuse_loop(fuse);
 
-    fuse_teardown(fuse, fd, mountpoint);
+    fuse_teardown(fuse, fd, setup.mountpoint);
     if (res == -1)
         return 1;
 
     return 0;
 }
 
+int fuse_main_parse (int argc, char *argv[], const struct fuse_operations *op,
+                     size_t op_size, int compat)
+{
+    int res = parse_cmdline (argc, argv);
+    if (res < 0)
+ return res;
+
+    return fuse_main_common (op, op_size, compat);
+}
+
 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
                    size_t op_size)
 {
-    return fuse_main_common(argc, argv, op, op_size, 0);
+    return fuse_main_parse(argc, argv, op, op_size, 0);
+}
+
+int fuse_main_parsed_real(const char * mountpoint,
+  const struct fuse_operations *op, size_t op_size)
+{
+    if (!mountpoint) {
+ usage (NULL);
+ free (setup.kernel_opts);
+ free (setup.lib_opts);
+ return -1;
+    }
+
+    setup.mountpoint = strdup (mountpoint);
+    return fuse_main_common(op, op_size, 0);
 }
 
 #undef fuse_main
@@ -422,17 +660,24 @@
     return -1;
 }
 
+#undef fuse_main_parsed
+int fuse_main_parsed ()
+{
+    fprintf(stderr, "fuse_main_parsed(): This function does not exist\n");
+    return -1;
+}
+
 void fuse_main_compat1(int argc, char *argv[],
                       const struct fuse_operations_compat1 *op)
 {
-    fuse_main_common(argc, argv, (struct fuse_operations *) op,
+    fuse_main_parse (argc, argv, (struct fuse_operations *) op,
                      sizeof(struct fuse_operations_compat1), 11);
 }
 
 int fuse_main_compat2(int argc, char *argv[],
                       const struct fuse_operations_compat2 *op)
 {
-    return fuse_main_common(argc, argv, (struct fuse_operations *) op,
+    return fuse_main_parse (argc, argv, (struct fuse_operations *) op,
                             sizeof(struct fuse_operations_compat2), 21);
 }
 

signature.asc (196 bytes) Download Attachment