root/src/add-ons/kernel/file_systems/userlandfs/server/fuse/helper.c
/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>

  This program can be distributed under the terms of the GNU LGPLv2.
  See the file COPYING.LIB.
*/

#include "config.h"
#include "fuse_api.h"
#include "fuse_misc.h"
#include "fuse_opt.h"
#include "fuse_lowlevel.h"
#include "fuse_common_compat.h"

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <sys/param.h>

enum  {
        KEY_HELP,
        KEY_HELP_NOHEADER,
        KEY_VERSION,
};

struct helper_opts {
        int singlethread;
        int foreground;
        int nodefault_subtype;
        char *mountpoint;
};

#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }

static const struct fuse_opt fuse_helper_opts[] = {
        FUSE_HELPER_OPT("-d",           foreground),
        FUSE_HELPER_OPT("debug",        foreground),
        FUSE_HELPER_OPT("-f",           foreground),
        FUSE_HELPER_OPT("-s",           singlethread),
        FUSE_HELPER_OPT("fsname=",      nodefault_subtype),
        FUSE_HELPER_OPT("subtype=",     nodefault_subtype),

        FUSE_OPT_KEY("-h",              KEY_HELP),
        FUSE_OPT_KEY("--help",          KEY_HELP),
        FUSE_OPT_KEY("-ho",             KEY_HELP_NOHEADER),
        FUSE_OPT_KEY("-V",              KEY_VERSION),
        FUSE_OPT_KEY("--version",       KEY_VERSION),
        FUSE_OPT_KEY("-d",              FUSE_OPT_KEY_KEEP),
        FUSE_OPT_KEY("debug",           FUSE_OPT_KEY_KEEP),
        FUSE_OPT_KEY("fsname=",         FUSE_OPT_KEY_KEEP),
        FUSE_OPT_KEY("subtype=",        FUSE_OPT_KEY_KEEP),
        FUSE_OPT_END
};

static void usage(const char *progname)
{
        fprintf(stderr,
                "usage: %s mountpoint [options]\n\n", progname);
        fprintf(stderr,
                "general options:\n"
                "    -o opt,[opt...]        mount options\n"
                "    -h   --help            print help\n"
                "    -V   --version         print version\n"
                "\n");
}

static void helper_help(void)
{
        fprintf(stderr,
                "FUSE options:\n"
                "    -d   -o debug          enable debug output (implies -f)\n"
                "    -f                     foreground operation\n"
                "    -s                     disable multi-threaded operation\n"
                "\n"
                );
}

static void helper_version(void)
{
        fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
}

static int fuse_helper_opt_proc(void *data, const char *arg, int key,
                                struct fuse_args *outargs)
{
        struct helper_opts *hopts = data;

        switch (key) {
        case KEY_HELP:
                usage(outargs->argv[0]);
                /* fall through */

        case KEY_HELP_NOHEADER:
                helper_help();
                return fuse_opt_add_arg(outargs, "-h");

        case KEY_VERSION:
                helper_version();
                return 1;

        case FUSE_OPT_KEY_NONOPT:
                if (!hopts->mountpoint) {
                        char mountpoint[PATH_MAX];
                        if (realpath(arg, mountpoint) == NULL) {
                                fprintf(stderr,
                                        "fuse: bad mount point `%s': %s\n",
                                        arg, strerror(errno));
                                return -1;
                        }
                        return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
                } else {
                        fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
                        return -1;
                }

        default:
                return 1;
        }
}

static int add_default_subtype(const char *progname, struct fuse_args *args)
{
        int res;
        char *subtype_opt;
        const char *basename = strrchr(progname, '/');
        if (basename == NULL)
                basename = progname;
        else if (basename[1] != '\0')
                basename++;

        subtype_opt = (char *) malloc(strlen(basename) + 64);
        if (subtype_opt == NULL) {
                fprintf(stderr, "fuse: memory allocation failed\n");
                return -1;
        }
        sprintf(subtype_opt, "-osubtype=%s", basename);
        res = fuse_opt_add_arg(args, subtype_opt);
        free(subtype_opt);
        return res;
}

int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
                       int *multithreaded, int *foreground)
{
        int res;
        struct helper_opts hopts;

        memset(&hopts, 0, sizeof(hopts));
        res = fuse_opt_parse(args, &hopts, fuse_helper_opts,
                             fuse_helper_opt_proc);
        if (res == -1)
                return -1;

        if (!hopts.nodefault_subtype) {
                res = add_default_subtype(args->argv[0], args);
                if (res == -1)
                        goto err;
        }
        if (mountpoint)
                *mountpoint = hopts.mountpoint;
        else
                free(hopts.mountpoint);

        if (multithreaded)
                *multithreaded = !hopts.singlethread;
        if (foreground)
                *foreground = hopts.foreground;
        return 0;

err:
        free(hopts.mountpoint);
        return -1;
}

int fuse_daemonize(int foreground)
{
        // On Haiku, always run "foreground", the userlandfs_server already takes care of running
        // as a server if needed.
        return 0;
}