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); } } }
/* 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); }
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); }
void main(int argc, char **argv) { struct opt_odb_t *odb; int n_int_vars, n_uint_vars, n_float_vars, n_double_vars; int n_enum_vars, n_enum_eval_vars, n_flag_vars, n_string_vars; int int_var, int_vars[MAX_VARS]; unsigned int uint_var, uint_vars[MAX_VARS]; float float_var, float_vars[MAX_VARS]; double double_var, double_vars[MAX_VARS]; int flag_var, flag_vars[MAX_VARS]; char *string_var, *string_vars[MAX_VARS]; enum etest_t { enum_a, enum_b, enum_c, enum_d, enum_NUM }; static char *enum_emap[enum_NUM] = { "enum_a", "enum_b", "enum_c", "enum_d" }; static int enum_eval[enum_NUM] = { enum_d, enum_c, enum_b, enum_a }; int enum_var, enum_vars[MAX_VARS]; int enum_eval_var, enum_eval_vars[MAX_VARS]; /* get an options processor */ odb = opt_new(f_orphan_fn); opt_reg_int(odb, "-opt:int", "This is an integer option.", &int_var, 1, /* print */TRUE, /* default format */NULL); opt_reg_int_list(odb, "-opt:int:list", "This is an integer list option.", int_vars, MAX_VARS, &n_int_vars, 2, /* print */TRUE, /* default format */NULL); opt_reg_uint(odb, "-opt:uint", "This is an unsigned integer option.", &uint_var, 3, /* print */TRUE, /* default format */NULL); opt_reg_uint_list(odb, "-opt:uint:list", "This is an unsigned integer list option.", uint_vars, MAX_VARS, &n_uint_vars, 4, /* print */TRUE, /* default format */NULL); opt_reg_float(odb, "-opt:float", "This is a float option.", &float_var, 5.0, /* print */TRUE, /* default format */NULL); opt_reg_float_list(odb, "-opt:float:list", "This is a float list option.", float_vars, MAX_VARS, &n_float_vars, 6.0, /* print */TRUE, /* default format */NULL); opt_reg_double(odb, "-opt:double", "This is a double option.", &double_var, 7.0, /* print */TRUE, /* default format */NULL); opt_reg_double_list(odb, "-opt:double:list", "This is a double list option.", double_vars, MAX_VARS, &n_double_vars, 8.0, /* print */TRUE, /* default format */NULL); opt_reg_enum(odb, "-opt:enum", "This is an enumeration option.", &enum_var, "enum_a", enum_emap, /* index map */NULL, enum_NUM, /* print */TRUE, /* default format */NULL); opt_reg_enum_list(odb, "-opt:enum:list", "This is a enum list option.", enum_vars, MAX_VARS, &n_enum_vars, "enum_b", enum_emap, /* index map */NULL, enum_NUM, /* print */TRUE, /* default format */NULL); opt_reg_enum(odb, "-opt:enum:eval", "This is an enumeration option w/eval.", &enum_eval_var, "enum_b", enum_emap, enum_eval, enum_NUM, /* print */TRUE, /* default format */NULL); opt_reg_enum_list(odb, "-opt:enum:eval:list", "This is a enum list option w/eval.", enum_eval_vars, MAX_VARS, &n_enum_eval_vars, "enum_a", enum_emap, enum_eval, enum_NUM, /* print */TRUE, /* default format */NULL); opt_reg_flag(odb, "-opt:flag", "This is a boolean flag option.", &flag_var, FALSE, /* print */TRUE, /* default format */NULL); opt_reg_flag_list(odb, "-opt:flag:list", "This is a boolean flag list option.", flag_vars, MAX_VARS, &n_flag_vars, TRUE, /* print */TRUE, /* default format */NULL); opt_reg_string(odb, "-opt:string", "This is a string option.", &string_var, "a:string", /* print */TRUE, /* default format */NULL); opt_reg_string_list(odb, "-opt:string:list", "This is a string list option.", string_vars, MAX_VARS, &n_string_vars, "another:string", /* print */TRUE, /* default format */NULL); /* parse options */ opt_process_options(odb, argc, argv); /* print options */ fprintf(stdout, "## Current Option Values ##\n"); opt_print_options(odb, stdout, /* long */FALSE, /* notes */TRUE); /* all done */ opt_delete(odb); exit(0); }