Example #1
0
File: opt.c Project: kainz/diod
int
opt_check_allowed_csv (Opt o, const char *csv)
{
    Opt allow;
    ListIterator itr;
    char *item, *cpy, *p;
    int ret = 0;

    NP_ASSERT (o->magic == OPT_MAGIC);

    allow = opt_create ();
    opt_addf (allow, "%s", csv);

    if (!(itr = list_iterator_create (o->list)))
        msg_exit ("out of memory");
    while ((item = list_next (itr))) {
        if (!(cpy = strdup (item)))
            msg_exit ("out of memory");
        if ((p = strchr (cpy, '=')))
            *p = '\0';
        if (!opt_find (allow, cpy)) {
            ret = 1;
            free (cpy);
            break;
        }
        free (cpy);
    }
    list_iterator_destroy (itr);

    opt_destroy (allow);
    return ret;
}
Example #2
0
static char *
_parse_spec (char *spec, Opt o)
{
    char *host, *aname;

    if (!(host = strdup (spec)))
        msg_exit ("out of memory");
    if ((aname = strchr (host, ':')))
        *aname++ = '\0';
    if (strlen (host) == 0)
        msg_exit ("no host specified");
    if (!aname || strlen (aname) == 0)
        ; /* aname = opt_find (o, "aname"); */
    else if (!opt_addf (o, "aname=%s", aname))
        msg_exit ("you cannot have both -oaname and spec=host:aname");

    return host;
}
Example #3
0
/* Private or public mount?  Only allow two modes:
 *    private:        -ouname=USER,access=UID (uname could be root)
 *    public (dflt):  -ouname=root,access=user
 */
static void
_parse_uname_access (Opt o)
{
    char *uname = opt_find (o, "uname");
    int uname_uid = -1;
    char *access = opt_find (o, "access");
    int access_uid = -1;
    char *access_name = NULL;
    struct passwd *pw;
    
    if (uname) {
        if (!(pw = getpwnam (uname)))
            msg_exit ("could not look up uname='%s'", uname);
        uname_uid = pw->pw_uid;
    }
    if (access && opt_scanf (o, "access=%d", &access_uid)) {
        if (!(pw = getpwuid (access_uid)))
            msg_exit ("could not look up access='%d'", access_uid);
        if (!(access_name = strdup (pw->pw_name)))
            msg_exit ("out of memory");
    }

    if (!uname && !access) {
        opt_addf (o, "uname=%s", "root");        
        opt_addf (o, "access=%s", "user");

    } else if (uname && !access) {
        if (uname_uid == 0)
            opt_addf (o, "access=%s", "user");
        else
            opt_addf (o, "access=%d", uname_uid);

    } else if (!uname && access) {
        if (strcmp (access, "user") == 0)
            opt_addf (o, "uname=%s", "root");
        else if (access_name) /* access=<uid> */
            opt_addf (o, "uname=%s", access_name);
        else
            msg_exit ("unsupported -oaccess=%s", access);
    } else { /* if (uname && access) */
        if (strcmp (access, "user") == 0) {
            if (uname_uid != 0)
                msg_exit ("-oaccess=user can only be used with -ouname=root");
        } else if (access_name) { /* access=<uid> */
            if (uname_uid != access_uid)
                msg_exit ("-oaccess=<uid> requires matching -ouname=<name>");
        } else
            msg_exit ("unsupported -oaccess=%s", access);
    } 
    if (access_name)
        free (access_name);
}
Example #4
0
/* Attach 9nbd device to remote file.
 */
static void
_nbd_attach (Opt o, int argc, char **argv, int nopt, int vopt)
{
    char *spec;
    char *host;
    char *addr;
    char *dev;
    char *path;
    int fd;
    char *options;
    int blksize = 4096;
    int uid;

    if (argc != 2)
        usage();
    spec = argv[0];
    dev = argv[1];

    _parse_nbdspec (spec, &host, &path);
    addr = _name2addr (host);

    if (!opt_find (o, "aname")) {
        opt_addf (o, "aname=%s", path);
        path = NULL;
    }
    if (!opt_find (o, "msize"))
        opt_addf (o, "msize=%d", DIOD_DEFAULT_MSIZE);

    if (opt_find (o, "trans=fd"))
        msg_exit ("9nbd doesn't work with trans=fd");
    if (!opt_find (o, "trans"))
        opt_addf (o, "trans=%s", "tcp");

    if (opt_find (o, "version") && !opt_find (o, "version=9p2000.L"))
        msg_exit ("9nbd only works with version=9p2000.L");
    if (!opt_find (o, "version"))
        opt_addf (o, "version=%s", "9p2000.L");

    if (!opt_find (o, "port"))
        opt_addf (o, "port=564");

    /* for 9nbd we require uid=<int> instead of uname=<str> */
    if (!opt_scanf (o, "uid=%d", &uid)) {
        char uname[256];
        if (opt_scanf (o, "uname=%255s", uname)) {
            uid = _uname2uid (uname);
            opt_delete (o, "uname");
        } else
            uid = 0;
        opt_addf (o, "uid=%d", uid);
    }

    if (!opt_find (o, "auth"))
        opt_addf (o, "auth=%s", "munge");

    options = opt_csv (o);

    if (!nopt) {
        fd = open (dev, O_RDWR);
        if (fd < 0 && (errno == ENOENT || errno == ENXIO)) {
            system ("/sbin/modprobe 9nbd");
            fd = open (dev, O_RDWR);
        }
        if (fd < 0)
            err_exit ("open %s", dev);
    }

    if (vopt)
        msg ("set blocksize=%d", blksize);
    if (!nopt && ioctl (fd, NBD_SET_BLKSIZE, blksize) < 0)
        err_exit ("ioctl set_blksize");

    if (vopt)
        msg ("set opts=%s", options);
    if (!nopt && ioctl (fd, NBD_SET_OPTS, options) < 0)
        err_exit ("ioctl set_opts");

    if (vopt)
        msg ("set addr=%s", addr);
    if (!nopt && ioctl (fd, NBD_SET_ADDR, addr) < 0)
        err_exit ("ioctl set_addr");

    if (vopt)
        msg ("set path=%s", path ? path : "null");
    if (!nopt && ioctl (fd, NBD_SET_PATH, path) < 0)
            err_exit ("ioctl set_path");

    if (vopt)
        msg ("start");
    if (!nopt && ioctl (fd, NBD_START) < 0)
        err_exit ("ioctl start");
    if (!nopt)
        close (fd);

    free (options);
    free (host);
    free (addr);
}
Example #5
0
int
main (int argc, char *argv[])
{
    char *dir = NULL;
    char *spec, *host;
    char *nspec = NULL;
    int c, i;
    int nopt = 0;
    int vopt = 0;
    int fopt = 0;
    int aopt = 0;
    int dopt = 0;
    int rfd = -1, wfd = -1;
    Opt o; 

    diod_log_init (argv[0]);

    o = opt_create ();

    opterr = 0;
    while ((c = GETOPT (argc, argv, OPTIONS, longopts)) != -1) {
        switch (c) {
            case 'f':   /* --fake-mount */
                fopt = 1;
                break;
            case 'n':   /* --no-mtab */
                nopt = 1;
                break;
            case 'v':   /* --verbose */
                vopt++;
                break;
            case 'o':   /* --options OPT[,OPT]... */
                opt_addf (o, "%s", optarg);
                break;
            case 'a':   /* --9nbd-attach */
                aopt++;
                break;
            case 'd':   /* --9nbd-detach */
                dopt++;
                break;
            default:
                usage ();
        }
    }

    /* Take care of 9nbd operations and exit.
     */
    if (aopt) {
        _nbd_attach (o, argc - optind, argv + optind, nopt, vopt);
        exit (0);
    }
    if (dopt) {
        _nbd_detach (o, argc - optind, argv + optind, nopt, vopt);
        exit (0);
    }

    if (optind != argc - 2)
        usage ();

    if (geteuid () != 0)
        msg_exit ("you must be root");

    spec = argv[optind++];
    dir = argv[optind++];
    host = _parse_spec (spec, o);

    _verify_mountpoint (dir);

    /* Remount - only pass mount flags into the VFS for an existing mount.
     * Take care of it here and exit.
     */
    if (opt_find (o, "remount")) {
        if (opt_check_allowed_csv (o, "ro,rw,aname,remount"))
            msg_exit ("-oremount can only be used with ro,rw");
        _diod_remount (o, spec, dir, vopt, fopt);
        goto done;
    }

    /* Ensure uname and access are set, and to diod-compatible values.
     * The uname user becomes the euid which will be used by munge auth.
     */
    _parse_uname_access (o);
     if (seteuid (_uname2uid (opt_find (o, "uname"))) < 0)
        err_exit ("seteuid");

    /* We require -otrans=fd because auth occurs in user space, then live fd
     * is passed to the kernel via -orfdno,wfdno.
     */
    if (!opt_find (o, "trans"))
        opt_addf (o, "trans=%s", "fd");
    else if (!opt_find (o, "trans=fd"))
        msg_exit ("only -otrans=fd transport is supported");

    /* Set msize if not already set.  Validate it later.
     */
    if (!opt_find (o, "msize"))
        opt_addf (o, "msize=%d", DIOD_DEFAULT_MSIZE);

    /* Only .L version is supported.
     */
    if (!opt_find (o, "version"))
        opt_addf (o, "version=%s", "9p2000.L");
    else if (!opt_find (o, "version=9p2000.L"))
        msg_exit ("only -oversion=9p2000.L is supported (little p, big L)");

    /* Set debug level.
     */
    if (!opt_find (o, "debug"))
        opt_addf (o, "debug=%d", 0x1); /* send errors to dmesg */

    /* Set rwdepth (number of concurrent reads with buffer > msize).
     * N.B. this option is not upstream yet but unknown options are ignored.
     */
    if (!opt_find (o, "rwdepth"))
        opt_addf (o, "rwdepth=%d", 1);

    /* Server is on an inherited file descriptor.
     * For testing, we start server on a socketpair duped to fd 0.
     */
    if (opt_find (o, "rfdno") || opt_find (o, "wfdno")) {
        if (!opt_scanf (o, "rfdno=%d", &rfd) || !opt_scanf (o, "wfdno=%d",&wfd))
            msg_exit ("-orfdno,wfdno must be used together");
        nopt = 1; /* force no mtab */

    /* Connect to server on UNIX domain socket
     */
    } else if (host[0] == '/') {
        if (opt_find (o, "port"))
            msg_exit ("-oport won't work with UNIX domain socket");
        if ((rfd = diod_sock_connect_unix (host, 0)) < 0)
            exit (1);
        wfd = rfd;

        opt_addf (o, "rfdno=%d", rfd);
        opt_addf (o, "wfdno=%d", wfd);

    /* Connect to server on IANA port (or user-specified) and host.
     */
    } else {
        char *port = opt_find (o, "port");
        hostlist_iterator_t hi;
        hostlist_t hl; 
        char *h;

        if (!port)
            port = "564";
        if (!(hl = hostlist_create (host)))
            msg_exit ("error parsing host string: %s", host);
        if (!(hi = hostlist_iterator_create (hl)))
            msg_exit ("out of memory");
        while ((h = hostlist_next (hi))) {
            if (vopt)
                msg ("trying to connect to %s:%s", h, port);
            if ((rfd = diod_sock_connect_inet (h, port, DIOD_SOCK_QUIET)) >= 0)
                break;
        }
        if (h) { /* create new 'spec' string identifying successful host */
            char *p = strchr (spec , ':');
            int len = strlen (h) + (p ? strlen (p) : 0) + 1;

            if (!(nspec = malloc (len)))
                msg_exit ("out of memory");
            snprintf (nspec, len, "%s%s", h, p ? p : "");
        }
        hostlist_destroy (hl);
        if (rfd < 0)
            msg_exit ("could not connect to server(s), giving up");
        wfd = rfd;
        
        opt_delete (o, "port");
        opt_addf (o, "rfdno=%d", rfd);
        opt_addf (o, "wfdno=%d", wfd);
    }

    NP_ASSERT (opt_find (o, "trans=fd"));
    NP_ASSERT (opt_scanf (o, "msize=%d", &i));
    NP_ASSERT (opt_find (o, "version=9p2000.L"));
    NP_ASSERT (opt_scanf (o, "debug=%d", &i) || opt_scanf (o, "debug=%x", &i));
    NP_ASSERT (opt_scanf (o, "wfdno=%d", &i) && opt_scanf (o, "rfdno=%d", &i));
    NP_ASSERT ((opt_find (o, "access=user") && opt_find(o, "uname=root"))
         || (opt_scanf (o, "access=%d", &i) && opt_find(o, "uname")));

    NP_ASSERT (!opt_find (o, "port"));

    _diod_mount (o, rfd, wfd, nspec ? nspec : spec, dir, vopt, fopt, nopt);

done:
    opt_destroy (o);
    exit (0);
}