Пример #1
0
static void
_diod_mount (Opt o, int rfd, int wfd, char *spec, char *dir, int vopt,
             int fopt, int nopt)
{
    char *options, *options9p, *aname, *uname;
    uid_t uid;
    int msize;
    Npcfsys *fs;
    Npcfid *afid, *root;
    unsigned long mountflags = 0;

    options = opt_csv (o);
    _getflags (o, &mountflags);
    options9p = opt_csv (o); /* after mountflags removed from opt list */

    if (!(uname = opt_find (o, "uname")))
        msg_exit ("uname is not set"); /* can't happen */
    uid = _uname2uid (uname);
    aname = opt_find (o, "aname"); /* can be null */
    if (!opt_scanf (o, "msize=%d", &msize) || msize < P9_IOHDRSZ)
        msg_exit ("msize must be set to integer >= %d", P9_IOHDRSZ);

    if (vopt)
        msg ("pre-authenticating connection to server");
    if (!(fs = npc_start (rfd, wfd, msize, 0)))
        errn_exit (np_rerror (), "version");
    if (!(afid = npc_auth (fs, aname, uid, diod_auth)) && np_rerror () != 0)
        errn_exit (np_rerror (), "auth");
    if (!(root = npc_attach (fs, afid, aname, uid))) {
        errn (np_rerror (), "attach");
        if (afid)
            (void)npc_clunk (afid);
        exit (1);
    }
    if (afid && npc_clunk (afid) < 0)
        errn_exit (np_rerror (), "clunk afid");
    if (npc_clunk (root) < 0)
        errn_exit (np_rerror (), "clunk root");
    if (vopt)
        msg ("mount -t 9p %s %s -o%s", spec, dir, options);
    if (!fopt) {
        /* kernel wants non-blocking */
        if (fcntl (rfd, F_SETFL, O_NONBLOCK) < 0)
            err_exit ("setting O_NONBLOCK flag on rfd=%d", rfd);
        if (fcntl (wfd, F_SETFL, O_NONBLOCK) < 0)
            err_exit ("setting O_NONBLOCK flag on wfd=%d", wfd);
        _mount (spec, dir, mountflags, options9p);
    }
    npc_finish (fs); /* closes fd */

    if (!nopt) {
        if (!_update_mtab (options, spec, dir))
            msg_exit ("failed to update /etc/mtab");
    }
    free (options);
    free (options9p);
}
Пример #2
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);
}
Пример #3
0
static int opt_process_one(struct opt_entry *list, opt_flags *flg, char *opt)
{
	char *param;
	struct opt_entry *entry;

	completed = NULL;

	param = opt_find(list, opt, &entry);
	if (!entry) return OPT_ERROR_UNKNOWN;

	if (*flg & entry->flg_set & entry->flg_clr) return OPT_ERROR_COMB;

	*flg &= ~entry->flg_clr;
	*flg |= entry->flg_set;

	if (entry->format) {
		if (!param) {
			if (entry->req_clr & OPT_REQ_PARAM)
				return OPT_ERROR_PARAM_REQ;
		} else
		if (opt_process_param(param, entry->format, entry->param))
			return OPT_ERROR_PARAM_INV;

		/* Dupe checking without an option flag */
		if (param && entry->flg_set == FLG_ZERO &&
		    entry->req_clr & OPT_REQ_PARAM && entry->param_set++)
			return OPT_ERROR_COMB;
	} else
	if (param) return OPT_ERROR_PARAM_EXT;

	return OPT_ERROR_NONE;
}
Пример #4
0
Файл: opt.c Проект: 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;
}
Пример #5
0
static int opt_process_one(struct opt_entry *list, opt_flags *flg, char *opt)
{
	char *param;
	struct opt_entry *entry;

	param = opt_find(list, opt, &entry);
	if (!entry) return OPT_ERROR_UNKNOWN;

	if (*flg & entry->flg_set & entry->flg_clr) return OPT_ERROR_COMB;

	*flg &= ~entry->flg_clr;
	*flg |= entry->flg_set;

	if (entry->format) {
		if (!param) {
			if (entry->req_clr & OPT_REQ_PARAM)
				return OPT_ERROR_PARAM_REQ;
		} else
		if (opt_process_param(param, entry->format, entry->param))
			return OPT_ERROR_PARAM_INV;
	} else
	if (param) return OPT_ERROR_PARAM_EXT;

	return OPT_ERROR_NONE;
}
Пример #6
0
int opt_get_val(const char *opt_name, char *buf, size_t len) {
	int i = opt_find(opt_name);

	if (i == -1)
		return (-1);

	switch (global_pref[i].type) {
		case OPT_BOOL:
			snprintf(buf, len, "%d", global_pref[i].val.b);
			break;

		case OPT_STR:
			if (global_pref[i].val.s == NULL)
				return (-1);
			xstrncpy(buf, global_pref[i].val.s, len);
			break;

		case OPT_INT:
			snprintf(buf, len, "%d", global_pref[i].val.i);
			break;

		case OPT_CHAR:
			snprintf(buf, len, "%c", global_pref[i].val.c);
			break;

		case OPT_COLOR:
			color_get_str(global_pref[i].val.i, buf, len);
			break;
	}

	return (0);
}
Пример #7
0
static void
_getflags (Opt o, unsigned long *flags)
{
    int i;

    for (i = 0; i < sizeof (setopt) / sizeof (map_t); i++) {
        if (opt_find (o, setopt[i].opt)) {
            *flags |= setopt[i].flag;            
            opt_delete (o, setopt[i].opt);
        }
    }
    for (i = 0; i < sizeof (clropt) / sizeof (map_t); i++) {
        if (opt_find (o, clropt[i].opt)) {
            *flags &= ~clropt[i].flag;            
            opt_delete (o, clropt[i].opt);
        }
    }
}
Пример #8
0
static int opt_check_one(struct opt_entry *list, opt_flags flg, char *opt)
{
	struct opt_entry *entry;

	opt_find(list, opt, &entry);
	if (!entry) return OPT_ERROR_UNKNOWN;

	if ((flg & entry->req_set) != entry->req_set || (flg & entry->req_clr))
		return OPT_ERROR_COMB;

	return OPT_ERROR_NONE;
}
Пример #9
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);
}
Пример #10
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);
}